'''
Name: srd_featureclass_info.py

Overview: Provides utilities for working with feature classes and layers.

Description:
    
    
Notes:

Author: Doug Crane
        May, 2012

Modifications:

'''

__author__ = 'Doug Crane'
__version__ = '1.0'

import sys
import os
import pdb

import arcpy

from srd_exception import *

__all__ = ['SRD_FeatureClassInfo']

# ====================================================================
class SRD_FeatureClassInfo(object):
    '''
    Provides information regarding the type of feature class
    contained in path to dataset.
    '''


    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def __init__(self, datasetPath):
        '''
        Initialize

        Variables:
            fullPath - full path to the dataset
            rawPath - same as datasetPath
            parentDir - parent directory for the dataset.
            
        Parameters:
            datasetPath - name of layer or path to dataset you wish to test.

        Examples:

            featureClass = r'D:\testData\avi\polygon'
            utilFC = SRD_FeatureClassInfo(featureClass)
            if utilFC.isCoverage():
                print 'Is Coverage'
            else:
                print 'Not Coverage'

            print 'Full Path: %s' % utilFC.getFullPath()
            print 'Workspace Dir: %s' % utilFC.getWorkspacePath()
            print 'Parent Dir: %s' % utilFC.getParentDir()

            featureClass = r'D:\testData\aviTest.gdb\avi1'
            utilFC = SRD_FeatureClassInfo(featureClass)
            if utilFC.isFGDB():
                print 'Is FGDB'
            else:
                print 'Not FGDB'

            print 'Full Path: %s' % utilFC.getFullPath()
            print 'Workspace Dir: %s' % utilFC.getWorkspacePath()
            print 'Parent Dir: %s' % utilFC.getParentDir()
            

            featureClass = r'D:\testData\myMdbTest.mdb\TILE10'
            utilFC = SRD_FeatureClassInfo(featureClass)
            if utilFC.isMDB():
                print 'Is MDB'
            else:
                print 'Not MDB'

            print 'Full Path: %s' % utilFC.getFullPath()
            print 'Workspace Dir: %s' % utilFC.getWorkspacePath()
            print 'Parent Dir: %s' % utilFC.getParentDir()
        
        '''

        # Make sure that dataset exists
        if not arcpy.Exists(datasetPath):
            raise SRD_Exception('Dataset: %s not found' % datasetPath)
        
        self.rawPath = datasetPath

        self.fullPath = ''
        self.getFullPath()

        self.parentDir = ''
        self.getParentDir()
        
        # List of descripe.DataType that are supported feature classes.
        self._featureClassList = ['featureclass','coveragefeatureclass','shapefile']

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def getParentDir(self):
        '''
        Sets the parent directory of the dataset.

        In the case of a feature class contained in an MDB or
        FGDB it will be the directory where the MDB or FGDB is stored.
        '''

        self.parentDir = ''
        
        # Must have the full path to feature class in order to extract
        # its parent directory.
        if self.fullPath:
            self.parentDir = self.fullPath
            while self.parentDir and not os.path.isdir(self.parentDir):
                self.parentDir = os.path.dirname(self.parentDir)

        # If we are dealing with a coverage or an FGDB then the coverage
        # or FGDB itself is a directory so we must move on level up to get
        # the true parent diectory.
        if self.isCoverage() or self.isFGDB():
            self.parentDir = os.path.dirname(self.parentDir)

        return self.parentDir
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def getFullPath(self):
        '''
        Sets the full path to dataset even if layer file.

        When using a geoprocessing tool the user may call the tool from
        ArcMap using an attached layer. In some cases you may need the
        full path to this layer. This routine will extract path from
        dataset even if it is a layer.
        
        Note that if it a layer then it is based on a single feature
        class and not a group layer. If cannot determine the data path
        then None is assigned as path and should be handled by calling
        routine.
        '''

        # If layer must extract feature class to obtain path.
        if self.isLayer():
            self.fullPath = arcpy.Describe(self.rawPath).Featureclass.CatalogPath
        else:
            self.fullPath = arcpy.Describe(self.rawPath).CatalogPath

        return self.fullPath
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def getFGDBPath(self):
        '''
        Returns the path to the FGDB if feature class is contained
        in one otherwise returns ""

        '''

        fgdbPath = ''
        
        # Must have the full path to feature class in order to extract
        # its FGDB path. Look for the .gdb extension of the FDGB and
        # return everything including the .gdb portion of path.
        if not self.fullPath:
            self.getFullPath()
            
        idx = self.fullPath.find('.gdb')
        if idx > 0:
            idx += 4
            fgdbPath = self.fullPath[:idx]
            
        return fgdbPath

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def getMDBPath(self):
        '''
        Returns the path to the MDB if feature class is contained
        in one otherwise returns ""

        '''


        mdbPath = ''
        
        # Must have the full path to feature class in order to extract
        # its FGDB path. Look for the .gdb extension of the FDGB and
        # return everything including the .gdb portion of path.
        if not self.fullPath:
            self.getFullPath()

        idx = self.fullPath.find('.mdb')
        if idx > 0:
            idx += 4
            mdbPath = self.fullPath[:idx]
            
        return mdbPath
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def getCoveragePath(self):
        '''
        Returns the path to the Coverage

        '''


        covPath = ''

        # Ensure have the full path.        
        if not self.fullPath:
            self.getFullPath()

        covPath = os.path.dirname(self.fullPath)

        return covPath

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def getWorkspacePath(self):
        '''
        Returns the path to the workspace that the feature class
        is contained in. If the workspace path cannot be determined
        then "" is returned

        '''


        # Return the workspace path depending of the container type.
        if self.isFGDB():
            wsPath = self.getFGDBPath()
        elif self.isMDB():
            wsPath = self.getMDBPath()
        elif self.isShapefile():
            wsPath = self.getParentDir()
        elif self.isCoverage():
            wsPath = self.getCoveragePath()
        else:
            wsPath = ''
        
        return wsPath

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def getFeatureDatasetName(self):
        '''
        If feature class is contained in a Feature Dataset then
        then its name is returned, otherwise '' is returned.
        '''

        datasetPath = os.path.dirname(self.fullPath)
        descObj = arcpy.Describe(datasetPath)

        if hasattr(descObj, 'datasetType'):
            if descObj.datasetType.upper() == 'FeatureDataset'.upper():
                return os.path.basename(datasetPath)
            else:
                return ''
        else:
            return ''
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isFeatureClass(self):
        '''
        Returns True if data is a feature class as opposed to tabele etc...

        Note that not all data types are supported. The dataset must be
        a feature type of : ['featureclass','coveragefeatureclass','shapefile']
        to be considered a feature class.
        '''

        descObj = arcpy.Describe(self.rawPath)
        if hasattr(descObj, 'datasetType'):
            return descObj.datasetType.upper() == 'FeatureClass'.upper()
        else:
            return False

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isTable(self):
        '''
        Returns True if data is a table

        '''

        descObj = arcpy.Describe(self.rawPath)
        if hasattr(descObj, 'datasetType'):
            return descObj.datasetType.upper() == 'Table'.upper()
        else:
            return False
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def geometryType(self):
        '''
        Returns the uppercase geometry type of feature class:

            Polygon 
            Polyline 
            Point 
            MultiPoint 
            MultiPatch 

        If no shape type then returns ''
        '''

        descObj = arcpy.Describe(self.rawPath)
        if hasattr(descObj, 'shapeType'):
            return descObj.shapeType.upper()
        else:
            return ''
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isGeometryType(self, typeName):
        '''
        Returns True if the feature class is a particular geometry type.

        Parameters:
            typeName - geometry type name to test, must be one of following:
                Polygon 
                Polyline 
                Point 
                MultiPoint 
                MultiPatch 
            
        '''

        descObj = arcpy.Describe(self.rawPath)
        if hasattr(descObj, 'shapeType'):
            return descObj.shapeType.upper() == typeName.upper()
        else:
            return False        
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isPolygonFC(self):
        '''
        Returns True if data is a polygon feature class.
        '''

        return self.isGeometryType('polygon')
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isPolylineFC(self):
        '''
        Returns True if data is a polyline feature class.
        '''

        return self.isGeometryType('polyline')        
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isLineFC(self):
        '''
        Returns True if data is a polyline feature class.
        '''

        return self.isGeometryType('polyline')        
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isPointFC(self):
        '''
        Returns True if data is a point feature class.
        '''

        return self.isGeometryType('point')
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isMultipointFC(self):
        '''
        Returns True if data is a multipoint feature class.
        '''

        return self.isGeometryType('multipoint')        
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isDataType(self, dataTypeName):
        '''
        Returns True if feature class is of a certain datatype

        Parameters:
            dataTypeName - name of the data type for the feature
                           class. Example: shapefile
        '''

        descObj = arcpy.Describe(self.rawPath)
        if hasattr(descObj, 'dataType'):
            return descObj.dataType.upper() == dataTypeName.upper()
        else:
            return False
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isShapefile(self):
        '''
        Returns True if data is from a shapefile.
        '''

        return self.isDataType('ShapeFile')
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isCoverage(self):
        '''
        Returns True if data from a coverage.
        '''

        return self.isDataType('CoverageFeatureClass')
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isFeatureLayer(self):
        '''
        Returns True if featue class is a feature layer. This
        is normally the case if passed from ArcMap table of
        contents.
        '''

        descObj = arcpy.Describe(self.rawPath)
        if hasattr(descObj, 'dataType'):
            return descObj.dataType.upper() == "FeatureLayer".upper()
        else:
            return False
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isLayer(self):
        '''
        Returns True if feature class is a layer such as from a layer file.
        '''

        descObj = arcpy.Describe(self.rawPath)
        if hasattr(descObj, 'dataType'):
            return descObj.dataType.upper() == "Layer".upper()
        else:
            return False
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isMDB(self):
        '''
        Returns True if data is contained in an MDB.
        '''
                
        return self.fullPath.lower().find('.mdb') >= 0
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def isFGDB(self):
        '''
        Returns True if data is contained in an FGDB.
        '''

        return self.fullPath.lower().find('.gdb') >= 0
    
            
# --------------------------------------------------------------------
if __name__ == '__main__':

    try:
        
        featureClass = r'D:\testData\util_tests\c5_cuts_2004\polygon'
        utilFC = SRD_FeatureClassInfo(featureClass)
        if utilFC.isCoverage():
            print 'Is Coverage'
        else:
            print 'Not Coverage'

        print 'Full Path: %s' % utilFC.getFullPath()
        print 'Workspace Dir: %s' % utilFC.getWorkspacePath()
        print 'Parent Dir: %s' % utilFC.getParentDir()

        featureClass = r'D:\testData\util_tests\aviTest.gdb\avi'
        utilFC = SRD_FeatureClassInfo(featureClass)
        if utilFC.isFGDB():
            print 'Is FGDB'
        else:
            print 'Not FGDB'

        print 'Full Path: %s' % utilFC.getFullPath()
        print 'Workspace Dir: %s' % utilFC.getWorkspacePath()
        print 'Parent Dir: %s' % utilFC.getParentDir()
        

        featureClass = r'D:\testData\util_tests\mdbTst.mdb\avi'
        utilFC = SRD_FeatureClassInfo(featureClass)
        if utilFC.isMDB():
            print 'Is MDB'
        else:
            print 'Not MDB'

        print 'Full Path: %s' % utilFC.getFullPath()
        print 'Workspace Dir: %s' % utilFC.getWorkspacePath()
        print 'Parent Dir: %s' % utilFC.getParentDir()

        featureClass = r'D:\testData\util_tests\tst.lyr'
        utilFC = SRD_FeatureClassInfo(featureClass)
        if utilFC.isLayer():
            print 'Is Layer'
        else:
            print 'Not Layer'

        print 'Full Path: %s' % utilFC.getFullPath()
        print 'Workspace Dir: %s' % utilFC.getWorkspacePath()
        print 'Parent Dir: %s' % utilFC.getParentDir()

    except SRD_Exception as e:
        print e.errMsg
        
    
    
    
