# ******************************************************
## Revision "$LastChangedDate: 2015-05-21 09:04:25 +0200 (Thu, 21 May 2015) $"
## Date "$LastChangedRevision: 503 $"
## Author "$LastChangedBy: arthurbeusen $"
## URL "$HeadURL: https://pbl.sliksvn.com/globalnutrients/generalcode/trunk/cmd_options_general.py $"
# ******************************************************

# Import general python modules
import os
import sys
import optparse
import getpass
import time
import copy

# Import own general modules
import ascraster
from error import *

# Switch debug messages on or off
_debug = False

def set_debug(val):
    global _debug
    _debug = val

def _dbg(msg):
    if _debug:
        print "DBG-->", msg

class Input(object):
    '''
    General functions for Parsing arguments and store them using the optparse module.

    Pass sys.argv into class: Input(sys.argv).
    Options will be included in 'options' object of instance of Input().
    Call options using:
    <instance>.options.<option>

    All other command-line arguments will be stored in <instance>.args
    '''

    def validate_file(self, file):
        '''
        Validate file

        Performs the following checks:
        * Check if file exists

        '''
        _dbg("Checking file: %s" % file)
        if not os.path.exists(file):
            raise MyError("File '%s' does not exist" % file)

    def validate_directory(self, directory, bool_write=True):
        '''
        Validate directory.

        Performs the following checks:
        * Check if directory exists
        * Check if directory is really a directory
        * if bool_write is True Check for write access on directory
        and raise an exception if validation fails

        '''
        _dbg("Checking directory: %s" % directory)
        if not os.path.exists(directory):
            raise MyError("Directory '%s' does not exist" % directory)
        elif not os.path.isdir(directory):
            raise MyError("Value '%s' is not a directory" % directory)
        elif bool_write:
            test_filename = os.path.join(directory, "DeleteMe.txt")
            try:
                file = open(test_filename,"w")
                file.close()
                os.remove(test_filename)
            except:
                raise MyError("You have no write access to '%s'" % directory)

    def _parse_inifile(self, list_args):
        '''
        Parse inifile and return list

        In inifile use command-line option notation, followed by '=', followed by argument, e.g. --inputdir = C:\temp.
        Comments must be preceded by '#'. Everything after '#' will be ignored by the parser.
        Command-line options prevail over inifile options.

        '''
        # Look for ini file in argument list
        inifile = list_args[list_args.index("--inifile")+1]
        # Check whether ini file exists
        self.validate_file(inifile)
        # Open ini file
        file = open(inifile,"r")
        ini_args_list = []
        for line in file.readlines():
            option = [elem.strip() for elem in line.split("#")[0].split("=")]
            # Check whether the first element is an option (first character is a dash)
            if option[0].startswith("-"):
                # If debug option is used in the ini file, activate the debug function
                if (option == '-d' or option == '--debug'):
                    set_debug(True)
                # Check the None type or logical value:
                if (option[1] == "None"):
                    option[1] = None
                elif (option[1] == "True"):
                    option[1] = True
                elif (option[1] == "False"):
                    option[1] = False

                # Add to the list
                ini_args_list.extend(option)
        # Close ini file
        file.close()

        # If debug option is found, write the options found in the ini file to screen.
        for option in ini_args_list:
            _dbg("Options or values found in inifile: %s" % option)

        return ini_args_list

    def _parse_parameter_inifile(self,cmd_class,inifile):
        '''
        Parse inifile with default parameters and return the class with this information

        In inifile use command-line option notation, followed by '=', followed by argument, e.g. P_bal_grass = "balance_P_grs.asc".
        Comments must be preceded by '#'. Everything after '#' will be ignored by the parser.
        The parameters are not set by the command-line options.

        '''
        # Check whether ini file exists
        self.validate_file(inifile)
        # Open ini file
        file = open(inifile,"r")
        for line in file.readlines():
            option = [elem.strip() for elem in line.split("#")[0].split("=")]
            if (len(option) == 2):
                # Add to the cmd_class
                try:
                    val = int(option[1])
                except ValueError:
                    try:
                        val = float(option[1])
                    except ValueError:
                        val = option[1]
                        # Check the None type or logical value:
                        if (option[1] == "None"):
                            val = None
                        elif (option[1] == "True"):
                            val = True
                        elif (option[1] == "False"):
                            val = False
                setattr(cmd_class,option[0],val)
        # Close ini file
        file.close()

    
    # Following functions are used to perform a sensitivity analyse.
    def _check_min(self,x,val_min):
        if (x < val_min): 
            return val_min
        else:
            return x

    def _check_max(self,x,val_max):
        if (x > val_max): 
            return val_max
        else:
            return x
     
    def _check_range(self,x,val_min,val_max):
        x1 = self._check_min(x,val_min)
        return self._check_max(x1,val_max)                      


    def label_present(self,name):
        try:          
            a = getattr(self.options,str(name))
            return True
        except AttributeError:
            return False

    def grid_mult_scalar(self,label,filename,xmin=None,xmax=None):
        '''
        Make a new grid file for a sensitivity analyse. Filename is changed to output directory.
        '''
        if (self.label_present(label)):
            print label + ' is found.'
            # Store old filename
            filename_old  = filename            
            filename  = os.path.join(self.options.outputdir,os.path.basename(filename_old))
            # Read input file
            grid=ascraster.Asciigrid(ascii_file=filename_old)
            grid.multiply(float(getattr(self.options,label)),minimum=xmin,maximum=xmax)
            grid.write_ascii_file(filename)
            del grid
        else:
            print label + ' is NOT found.'

        # Return new file name
        return filename        

    def grid_add_scalar(self,label,filename,minimum=None, maximum=None):
        '''
        Make a new grid file for a sensitivity analyse. Filename is changed to output directory.
        '''
        if (self.label_present(label)):
            print label + ' is found.'
            # Store old filename
            filename_old  = filename
            filename  = os.path.join(self.options.outputdir,os.path.basename(filename_old))
            # Read input file
            grid=ascraster.Asciigrid(ascii_file=filename_old)
            grid.add(float(getattr(self.options,label)),minimum=minimum,maximum=maximum)
            grid.write_ascii_file(filename)
            del grid
        else:
            print label + ' is NOT found.'        

        # Return new file name
        return filename 

def make_parameter_list(obj,basename):
    '''
    This function puts the given information from the parameters input file into one structure.
    All parameters of params.<basename>* are joined together in a list.
    The joined information is put back in the params.<basename>_list object.
    '''
    try:
        # Check whether this parameter is already set. 
        # When it is set, then do nothing.
        #print str(basename)+"_list"
        qq = getattr(obj,str(basename)+"_list")
    except AttributeError:
        counter = 1
        listout = []
        lfound = True
        while (lfound):
            try:
                #print basename + str(counter),getattr(obj,str(basename)+str(counter))
                val = getattr(obj,str(basename)+str(counter))
                listout.append(val)
                counter += 1
            except AttributeError:
                lfound = False

        # Check whether there is information found.
        if (listout == []):
            raise MyError("There is no information found like "+str(basename)+"1 in the parameters object.")

        # Put new list in the params object    
        setattr(obj,str(basename)+"_list",copy.deepcopy(listout))

