"""
 Tool Name:  CreateTopology
 Description: Creates updated polygon feature classes from updated lines feature class
 Author: Patrick Longley (plongley@usgs.gov)
 Created: 09/17/2020
 Language: Written in python3 (arcpro). Does not work in python2 (arcmap).
 History:
    20201006 metadata,
    20201006 constants,
    20201006 validation
    10/14/2020 general review
 TODO: differently spelled rules for arcmap
"""

import os
import sys
import arcpy
import wbd_params
import wbd_f
import wbd_c

# Constants
PYTHON_VERSION = sys.version_info.major
POLYGON_R1 = "Must Not Overlap (Area)"
POLYGON_R2 = "Must Not Have Gaps (Area)"
POLYGON_R3 = "Boundary Must be Covered By (Area-Line)"

class CreateTopology(object):
    """
    Creates topology using updated WBD feature classes

    Args:
        linefc_updated (str): Updated WBD line featureclass
        updatedpolygons_fc (list of strings): Update WBD polygon featureclasses (WBDHU10 and WBDHU12 or WBDHU10, WBDHU12, and WBDHU14)

    Outputs:
        returns: None
    """
    def __init__(self):
        """
        Initialize variables
        """
        self.label       = "G1 Create Topology"
        self.description = "Creates line/polygon topology"
        self.callfrom_pyt = True
        self.category = 'Geometry checks'

    def getParameterInfo(self):
        """
        Define the parameters for use in arcmap/pro.
        """
        params = [wbd_params.linefc_updated,
                  wbd_params.updatedpolygons_fc]
        return params

    def updateParameters(self, params):
        """
        Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parmater
        has been changed.
        """
        if params[0].altered and params[0].value and not params[1].value:
            feature = params[0].valueAsText
            lines_fpath = wbd_f.get_fpath(feature)
            # assume all feature classes are in the same feature dataset
            fd = os.path.dirname(lines_fpath)
            db = os.path.dirname(fd)
            with arcpy.EnvManager(workspace=db):
                fc_list = arcpy.ListFeatureClasses(feature_dataset=os.path.basename(fd), feature_type='Polygon')
            fc_list = [x for x in fc_list if x in ('HU10', 'HU12', 'HU14')]
            params[1].value = fc_list

    def updateMessages(self, params):
        """
        Modify the messages created by internal validation for each tool
        parameter.This method is called after internal validation.
        """
        if params[1].altered and params[1].value:
            fcs = {os.path.basename(x) for x in params[1].valueAsText.split(';')}
            if fcs != {'WBDHU10', 'WBDHU12'} and fcs != {'WBDHU10', 'WBDHU12', 'WBDHU14'}:
                message = 'Must enter either (WBDHU10 and WBDHU12) or (WBDHU10, WBDHU12, and WBDHU14).'
                params[1].setErrorMessage(message)

    def create_linetopology(self):
        """
        Create line topology.
        """
        with arcpy.EnvManager(overwriteOutput=True):
            line_topology = arcpy.CreateTopology_management(self.fdpath, wbd_c.LINETOPOLOGY)
            try:
                arcpy.AddFeatureClassToTopology_management(line_topology, self.linefc_updated)
            except arcpy.ExecuteError:
                if self.callfrom_pyt:
                    arcpy.arcpy.AddError(('Topology not created. '
                                        'Line feature class already participates in a topology. '
                                        'Delete preexisting topologies before creating a new topology.'))
                else:
                    arcpy.arcpy.AddWarning(('Topology not created. '
                                        'Line feature class already participates in a topology. '
                                        'Delete preexisting topologies before creating a new topology.'))
            else:
                arcpy.AddRuleToTopology_management(line_topology,
                                                "Must Not Overlap (Line)",
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(line_topology,
                                                "Must Not Intersect (Line)",
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(line_topology,
                                                "Must Not Have Dangles (Line)",
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(line_topology,
                                                "Must Not Have Pseudo-Nodes (Line)",  #no dash in arcmap?
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(line_topology,
                                                "Must Not Self-Overlap (Line)",   #Self Overlap >>> Self-Overlap in arcmap
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(line_topology,
                                                "Must Be Single Part (Line)",
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(line_topology,
                                               "Must Not Intersect Or Touch Interior (Line)",
                                               self.linefc_updated)

    def create_polygontopology(self):
        """
        Create topology including lines and polygons.
        """
        huc10_fc = self.updatedpolygons_fc[0]
        huc12_fc = self.updatedpolygons_fc[1]
        if len(self.updatedpolygons_fc) == 3:
            huc14_fc = self.updatedpolygons_fc[2]
        else:
            huc14_fc = None
        with arcpy.EnvManager(overwriteOutput=True):
            polygon_topology = arcpy.CreateTopology_management(self.fdpath, wbd_c.POLYGONTOPOLOGY)
            try:
                arcpy.AddFeatureClassToTopology_management(polygon_topology, self.linefc_updated)
                arcpy.AddFeatureClassToTopology_management(polygon_topology, huc10_fc)
                arcpy.AddFeatureClassToTopology_management(polygon_topology, huc12_fc)
                if huc14_fc:
                    arcpy.AddFeatureClassToTopology_management(polygon_topology, huc14_fc)
            except arcpy.ExecuteError:
                if self.callfrom_pyt:
                    arcpy.arcpy.AddError(('Topology not created. '
                                        'One or more feature classes already participates in a topology. '
                                        'Delete preexisting topologies before creating a new topology.'))
                else:
                    arcpy.arcpy.AddWarning(('Topology not created. '
                                        'One or more feature classes already participates in a topology. '
                                        'Delete preexisting topologies before creating a new topology.'))
            else:
                # line rules
                arcpy.AddRuleToTopology_management(polygon_topology,
                                        "Must Not Have Dangles (Line)",
                                        self.linefc_updated)
                arcpy.AddRuleToTopology_management(polygon_topology,
                                                "Must Not Self-Overlap (Line)",   #Self Overlap >>> Self-Overlap in arcmap
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(polygon_topology,
                                                "Must Not Self-Intersect (Line)",
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(polygon_topology,
                                                "Must Not Have Pseudo-Nodes (Line)",  #no dash in arcmap?
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(polygon_topology,
                                                "Must Not Overlap (Line)",   #Self Overlap >>> Self-Overlap in arcmap
                                                self.linefc_updated)
                arcpy.AddRuleToTopology_management(polygon_topology,
                                                "Must Not Intersect Or Touch Interior (Line)",
                                                self.linefc_updated)
                # huc10 rules
                arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R1, huc10_fc)
                arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R2, huc10_fc)
                arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R3, huc10_fc, in_featureclass2=self.linefc_updated)
                # huc12 rules
                arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R1, huc12_fc)
                arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R2, huc12_fc)
                arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R3, huc12_fc, in_featureclass2=self.linefc_updated)
                # huc14_rules
                if huc14_fc:
                    arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R1, huc14_fc)
                    arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R2, huc14_fc)
                    arcpy.AddRuleToTopology_management(polygon_topology, POLYGON_R3, huc14_fc, in_featureclass2=self.linefc_updated)
                    arcpy.AddRuleToTopology_management(polygon_topology,
                                                       "Must be Covered By (Area-Area)",
                                                       huc14_fc,
                                                       in_featureclass2=huc12_fc)

    def execute(self, params, messages):
        """
        Creates topology
        """
        # parameters
        if self.callfrom_pyt:
            self.linefc_updated = params[0].valueAsText
            self.updatedpolygons_fc = params[1].valueAsText
        else:
            self.linefc_updated = params[0]
            self.updatedpolygons_fc = params[1]
        # create line/polygon topology
        try:
            self.updatedpolygons_fc = self.updatedpolygons_fc.split(';')
        except AttributeError:
            pass
        line_fpath = wbd_f.get_fpath(self.linefc_updated)
        self.fdpath = os.path.dirname(line_fpath)
        if self.updatedpolygons_fc:
            self.updatedpolygons_fc.sort()
            self.create_polygontopology()
        else:
            self.create_linetopology()

if __name__ == '__main__':
    """
    Execute as standalone script.
    """
    createtopology = CreateTopology()
    createtopology.callfrom_pyt = False
    arcpy.env.workspace = r'C:\GIS_Project\WBD\AK\Work\hu19010204\19010204_project\19010204_project.gdb'
    polygons = [r"C:\GIS_Project\WBD\AK\Work\hu19010204\19010204_project\19010204_project.gdb\Layers\HU10",
                r"C:\GIS_Project\WBD\AK\Work\hu19010204\19010204_project\19010204_project.gdb\Layers\HU12",
                r"C:\GIS_Project\WBD\AK\Work\hu19010204\19010204_project\19010204_project.gdb\Layers\HU14"]
    line = r"C:\GIS_Project\WBD\AK\Work\hu19010204\19010204_project\19010204_project.gdb\Layers\NewLines"
    params = (line, None)
    createtopology.execute(params, None)

