from sextante.outputs.Output import Output
from sextante.parameters.Parameter import Parameter
from sextante.core.QGisLayers import QGisLayers
from sextante.parameters.ParameterRaster import ParameterRaster
from sextante.parameters.ParameterVector import ParameterVector
from PyQt4 import QtGui
import os.path
from sextante.core.SextanteUtils import SextanteUtils
from sextante.parameters.ParameterMultipleInput import ParameterMultipleInput
from sextante.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException

class GeoAlgorithm:

    def __init__(self):
        #parameters needed by the algorithm
        self.parameters = list()
        #outputs generated by the algorithm
        self.outputs = list()
        self.name = ""
        self.group = ""
        #the crs taken from input layers (if possible), and used when loading output layers
        self.crs = None
        #change any of the following if your algorithm should not appear in the toolbox or modeler
        self.showInToolbox = True
        self.showInModeler = True
        #true if the algorithm has been canceled while it was being executed
        #default value is false, so it should be changed in processAlgorithm only if the algorithm
        #gets canceled
        self.canceled = False

        self.defineCharacteristics()

    #methods to overwrite when creating a custom geoalgorithm
    #=========================================================
    def getIcon(self):
        return QtGui.QIcon(os.path.dirname(__file__) + "/../images/alg.png")

    def helpFile(self):
        '''Returns the path to the help file with the description of this algorithm.
        It should be an HTML file'''
        return None

    def processAlgorithm(self):
        '''here goes the algorithm itself'''
        pass

    def defineCharacteristics(self):
        '''here is where the parameters and outputs should be defined'''
        pass

    def getCustomParametersDialog(self):
        '''if the algorithm has a custom parameters dialog, it should be returned
        here, ready to be executed'''
        return None

    def getCustomModelerParametersDialog(self, modelAlg):
        '''if the algorithm has a custom parameters dialog when called from the modeler,
        it should be returned here, ready to be executed'''
        return None

    #=========================================================

    def execute(self, progress):
        '''The method to use to call a SEXTANTE algorithm.
        Although the body of the algorithm is in processAlgorithm(),
        it should be called using this method, since it performs
        some additional operations.
        The return value indicates whether the algorithm was canceled (false)
        or successfully run (true).
        Raises a GeoAlgorithmExecutionException in case anything goes wrong.'''
        self.setOutputCRSFromInputLayers()
        self.resolveTemporaryOutputs()
        try:
            self.processAlgorithm(progress)
            return not self.canceled
        except GeoAlgorithmExecutionException, gaee:
            raise gaee
        except Exception, e:
            #if something goes wrong and is not catched in the algorithm,
            #we catch it here and wrap it
            raise GeoAlgorithmExecutionException(str(e))

    def resolveTemporaryOutputs(self):
        '''sets temporary outputs (output.value = None) with a temporary file instead'''
        for out in self.outputs:
            if (not out.hidden) and out.value == None:
                SextanteUtils.setTempOutput(out, self)

    def setOutputCRSFromInputLayers(self):
        layers = QGisLayers.getAllLayers()
        for param in self.parameters:
            if isinstance(param, (ParameterRaster, ParameterVector ,ParameterMultipleInput)):
                inputlayers = param.value.split(";")
                for inputlayer in inputlayers:
                    for layer in layers:
                        if layer.source() == inputlayer:
                            self.crs = layer.crs()
                            return


    def addOutput(self, output):
        #TODO: check that name does not exist
        if isinstance(output, Output):
            self.outputs.append(output)

    def addParameter(self, param):
        #TODO: check that name does not exist
        if isinstance(param, Parameter):
            self.parameters.append(param)

    def setParameterValue(self, paramName, value):
        for param in self.parameters:
            if param.name == paramName:
                param.value = value

    def setOutputValue(self, outputName, value):
        for out in self.outputs:
            if out.name == outputName:
                out.value = value

    def getVisibleOutputsCount(self):
        '''returns the number of non-hidden outputs'''
        i = 0;
        for out in self.outputs:
            if not out.hidden:
                i+=1
        return i;

    def getOutputValuesAsDictionary(self):
        d = {}
        for out in self.outputs:
            d[out.name] = out.value
        return d


    def __str__(self):
        s = "ALGORITHM: " + self.name + "\n"
        for param in self.parameters:
            s+=("\t" + str(param) + "\n")
        for out in self.outputs:
            if not out.hidden:
                s+=("\t" + str(out) + "\n")
        s+=("\n")
        return s


    def commandLineName(self):
        return self.provider.getName().lower().replace(" ", "") + ":" + self.name.lower().replace(" ", "").replace(",","")

    def removeOutputFromName(self, name):
        for out in self.outputs:
            if out.name == name:
                self.outputs.remove(out)

    def getOutputFromName(self, name):
        for out in self.outputs:
            if out.name == name:
                return out

    def getParameterFromName(self, name):
        for param in self.parameters:
            if param.name == name:
                return param

    def getParameterValue(self, name):
        for param in self.parameters:
            if param.name == name:
                return param.value
        return None

    def getOutputValue(self, name):
        for out in self.outputs:
            if out.name == name:
                return out.value
        return None

    def getAsCommand(self):
        '''Returns the command that would run this same algorithm from the console'''
        s="Sextante.runalg(\"" + self.commandLineName() + "\","
        for param in self.parameters:
            s+=param.getValueAsCommandLineParameter() + ","
        for out in self.outputs:
            s+=out.getValueAsCommandLineParameter() + ","
        s= s[:-1] + ")"
        return s
