import os
import re
import copy
import warnings
import flopy
import tempfile
import numpy as np
import prms_python as pp
from collections import OrderedDict
from datetime import datetime
from shutil import copyfile

class Control(OrderedDict):
    """
    Simple python data storage class that operates as an ordered dictionary.
    Class allows the user to create new, load existing, edit, and write
    GSFLOW control files.
    Simple consistancy checking is used to assure data is of proper type
    and number
    Record values can be called from the Control object using a dictionary key.

    Parameters:
    -----------
        controlfile: (str) name of the control file

    Methods:
    --------
        get_record: record handling class, retrieves complete metadata of a
                    record
        add_record: record handling class, adds a complete metadata record
        remove_record: record handling class, removes a record from the Control
                       object
        write: method to write data stored in the Control object to a control
               file
        load: static method to load existing an existing control file

    Attributes:
    -----------
        header: (str) Header string for the GSFLOW control file

    """
    def __init__(self, controlfile):
        # instantiate the OrderedDictionary override
        super(Control, self).__init__()

        self.header = 'GSFLOW control file built using GSFlowPy\n'
        self.name = controlfile

        if isinstance(controlfile, file):
            self.name = controlfile.name
            self.__controlfile = controlfile
            self.__get_params()

    def __getitem__(self, key):
        return super(Control, self).__getitem__(key)['val']

    def __setitem__(self, key, value):
        if type(value) is dict:
            rec = value
            rec = self.__check_record(rec)
        else:
            try:
                rec = self.get_record(key)
                rec['val'] = value
                rec = self.__check_record(rec)
            except KeyError:
                raise KeyError('record does not exist, create new record ' +
                               'using the <add_record> method')
        super(Control, self).__setitem__(key, rec)

    def __get_params(self):
        """
        Method to read parameters from an existing GSFLOW control file and
        create a record of data for each parameter within the Control object
        """
        position = 0
        name = None
        nval = None
        dtype = None
        val = []
        self.header = self.__controlfile.readline()
        # maybe use enumerate to track position?
        for line in self.__controlfile:
            if "#" in line:
                # we want to skip the fist instance of ###
                position = 0
                if name is not None:
                    # remove list dimension from data if it is not needed
                    if nval == 1:
                        val = val[0]

                    if name in ('start_time', 'end_time'):
                        # create a datetime object where appropriate
                        val = datetime(val[0], val[1], val[2],
                                       val[3], val[4], val[5])

                    rec = dict(name=name,
                               dtype=dtype,
                               nval=nval,
                               val=val)

                    super(Control, self).__setitem__(name, rec)

                    name = None
                    dtype = None
                    val = []

            elif position == 1:
                line = line.strip().split()
                name = str(line[0])

            elif position == 2:
                line = line.strip().split()
                nval = int(line[0])

            elif position == 3:
                line = line.strip().split()
                dtype = int(line[0])

            elif position > 3:
                line = line.strip().split()

                if dtype == 1:
                    val.append(int(line[0]))

                elif dtype in (2, 3):
                    val.append(float(line[0]))

                elif dtype == 4:
                    val.append(str(line[0]))

            position += 1

    def __check_record(self, rec):
        """
        Defensive method to check for consistancy of data type and length
        Parameters:
        -----------
            rec: (dict) Data record containing parameter metadata and data

        Returns:
        --------
            rec: (dict) Data record containing parameter metadata and data
        """
        if rec['name'] in ('start_time', 'end_time'):
            assert isinstance(rec['val'], datetime), 'time object:n {} must' + \
                                                     'be a datetime object'\
                                                     .format(rec['name'])
        else:

            rec = self.__check_nval(rec)
            if rec['nval'] == 1:
                self.__check_dtype(rec['nval'], rec['dtype'])

            elif rec['nval'] > 1:
                for val in rec['val']:
                    self.__check_dtype(val, rec['dtype'])

            else:
                raise StandardError('No data supplied for {}'
                                    .format(rec['name']))

        return rec

    def __check_dtype(self, val, dtype):
        """
        Convience method to check a value against its documented dtype
        Parameters:
        -----------
            val: value to be checked for consistancy with its listed dtype
            dtype: (int) GSFLOW control file dtype (1: int, 2: float, 3: float,
                         4: string
        """

        if dtype == 1:
            assert isinstance(val, int), 'listed dtype INT does not match' + \
                                         ' value supplied'

        elif dtype in (2, 3):
            try:
                float(val)
            except ValueError:
                assert isinstance(val, float), 'listed dtype FLOAT does not' + \
                                               ' match value supplied'

        elif dtype == 4:
            assert isinstance(val, str), 'listed dtype STR does not match' + \
                                         ' value supplied'

        else:
            raise AssertionError('dtype {} is not valid'.format(dtype))

    def __check_nval(self, rec):
        """
        Convience method to check adjust nval if necessary.

        Parameters
        ----------
            rec: (dict) GSFLOW control record

        Returns
        -------
            rec: (dict) GSFLOW control record
        """
        val = rec['val']

        if isinstance(val, int):
            rec['nval'] = 1

        elif isinstance(val, list):
            nval = len(val)
            rec['nval'] = nval

        return rec

    def get_record(self, key):
        """
        Method to get all data from a record of the control file dictionary
        Parameters:
        -----------
            key: (str) GSFLOW control record parameter name
        Returns:
        --------
            record: (dict) dictionary of data corresponding to the control
                           record
        """
        return super(Control, self).__getitem__(key)

    def add_record(self, name, nval, dtype, val):
        """
        Convience method to add records to Control object, or overwrite existing
        Control records.
        Parameters:
        -----------
            name: (str) gsflow record name
            nval: (int) number of values for the record (time objects = 6)
            dtype: (int) datatype specified in the gsflow documentation
            val: value(s) multiple values must be supplied in list format
        """
        rec = dict(name=name, nval=nval, dtype=dtype, val=val)
        self.__setitem__(name, rec)

    def remove_record(self, name):
        """
        Convience method to delete a record from the Control object
        Parameters:
        -----------
            name: (str) gsflow record name
        """
        self.pop(name, None)

    def write(self, controlfile=None):
        """
        Method to write records to a new gsflow control file
        Parameters:
        -----------
            controlfile: (str) file name for gsflow control file
        """
        if controlfile is None:
            controlfile = self.name
        else:
            self.name = controlfile

        # check if path exists
        controlfile = controlfile.replace('/', '\\')
        path = '\\'.join(controlfile.split('\\')[:-1])

        if os.path.exists(path):
            controlfile = open(controlfile, 'w')
        else:
            os.makedirs(path)
            controlfile = open(controlfile, 'w')

        # check header for newline
        if self.header[-1] != '\n':
            self.header += '\n'

        controlfile.write(self.header)

        for key in self:
            rec = self.get_record(key)

            if rec['name'] in ('start_time', 'end_time'):
                # re-format datetime object into string for gsflow control
                val = rec['val']
                dt = '{}\n{}\n{}\n{}\n{}\n{}'.format(val.year,
                                                     val.month,
                                                     val.day,
                                                     val.hour,
                                                     val.minute,
                                                     val.second)
                rec['val'] = dt

            elif rec['nval'] > 1:
                # re-format list object into string for gsflow control
                val = ''
                for i in rec['val']:
                    val += '{}\n'.format(i)
                rec['val'] = val[:-1]

            else:
                pass

            # write records to control file
            rec = '####\n{}\n{}\n{}\n{}\n'.format(rec['name'],
                                                  rec['nval'],
                                                  rec['dtype'],
                                                  rec['val'])

            controlfile.write(rec)

        controlfile.close()

    @staticmethod
    def load(controlfile):
        """
        Entry point to an existing GSFLOW control file
        Parameters:
        ----------
            controlfile: (str) GSFLOW control file name
        """
        return Control(open(controlfile, 'r'))

class ModelUtils(object):
    """
    Class containing useful model utilities to manage workspaces,
    etc ...
    Parameters:
    ----------
        ws: (str) model workspace (path containing the GSFLOW controlfile)
    """

    def __init__(self, ws):

        self.ws = ws
        # set up wsl

        self.__wsl = re.split('\/|\\\\|', ws)
        self.__wsl[0] += '\\'

    @property
    def _output_keys(self):
        return ('csv_output_file', 'gsflow_output_file',
                'mondel_output_file','humidity_day',
                'tmax_day', 'tmin_day', 'precip_day',
                'swrad_day', 'transp_day', 'windspeed_day',
                'potet_day', 'stat_var_file', 'var_init_file',
                'var_save_file', 'ani_output_file','nhruOutBaseFileName')

    def get_path(self, path):
        """
        Method to change the workspace path from control file
        to location of prms model files and/or modflow model files
        using path information contained in the control file.

        Parameters:
        -----------
            path: (str) relative or absolute file path

        Returns:
        --------
            path: (str) absolute file path
        """
        pathlist = re.split('\/|\\\\|', path)

        # check for absolute path
        if ':' in pathlist[0]:
            pathlist[0] += '\\'
            path = os.path.join(*pathlist)

        else:
            wsl = copy.copy(self.__wsl)
            for cd in pathlist:
                if cd == "..":
                    del wsl[-1]
                else:
                    wsl.append(cd)

            path = os.path.join(*wsl)

        return path

    def create_temp_modflow_nam_file(self, nam):
        """
        Creates a temporary nam file in the gsflow directory
        because flopy assumes a workspace based on location of the
        modflow nam, not the location of the gsflow.control file.

        Parameters:
        ----------
            nam: (str) path to modflow nam file

        Returns:
        --------
            temp_nam: (str) returns the temporary modflow nam file name
        """
        idx = - nam[::-1].index('\\')
        temp_nam = nam[idx:]
        temp_path = os.path.join(self.ws, temp_nam)
        copyfile(nam, temp_path)
        return temp_nam

    def create_temp_prms_file(self, prms):
        """
        Method to create temporary prms files if there is more than
        one file of that type. Necessary method for prms_python to load
        multiple parameter and data files.

        Parameters:
        -----------
            prms: (list) list of absolute file paths to prms files

        Returns:
        --------
            path: (string) path to temp prms file
            d: (OrderedDict) {filename: [final param]} to preseve user file
                              structure and orginization during the write
                              methods
        """

        suffix = prms[0].split('.')[-1]
        temp_file = tempfile.NamedTemporaryFile(suffix=suffix,
                                                prefix='GSFloPyTemp',
                                                dir=self.ws, delete=False)
        d = OrderedDict()
        temp = None
        for prms_file in prms:
            with open(prms_file) as f:
                reverse_prms_file = reversed(list(f))
                for line in reverse_prms_file:
                    if '#' in line:
                        d[prms_file.split('\\')[-1]] = temp.strip('\n')
                        break
                    temp = line

            with open(prms_file) as f:
                temp_file.writelines(f.readlines())

        temp_file.close()
        return temp_file.name, d

    @staticmethod
    def rename_and_move_files(src, dest):
        """
        Method to rename, and move temp files as needed while during the
        Loading, editing and writing process.

        Parameters:
        -----------
        src: (str) file source location and name
        dest: (str) file destination
        """
        os.rename(src, dest)

    @staticmethod
    def split_path(path):
        """
        Method to extract only the specific file name or path from any
        path. May be irrelevent with some additional work.

        Parameters:
        ----------
            path: (str) absolute path a file

        Returns:
        --------
            path, name (str) filename
        """
        path = re.split('\/|\\\\|', path)
        if len(path) == 1:
            return None, path[-1]
        else:
            return '\\'.join(list(path[:-1])), path[-1]

class PRMSModel(ModelUtils):
    """
    Wrapper class for the PRMS python module used as a wrapper around the prms
    python suite. Uses a GSFlow Control file to either load or create new prms
    objects

    Parameters:
    -----------
    controlfile: (str, object <gsflow.Control>) name of gsflow control file for
                 building new prms files. if <gsflow.Control> object class loads
                 existing prms files.

    ws: (str) gsflow model workspace

    Attributes:
    -----------

    Methods:
    --------
    load: loads existing PRMS model files
    """
    # todo: look into the PRMS init_vars_from_file and var_init_file,
    # todo: formatting and if we can read in/out these using existing code
    # todo: structures
    def __init__(self, controlfile, ws):
        super(PRMSModel, self).__init__(ws)
        self.__parameter_files = []
        self.__parameter_files_dict = {}
        self.__data_files = []
        self.__data_files_dict = {}
        self.__header = "PRMS parameters file created with GSFloPy 0.1\n"
        self.__version = "Version: 1.7\n"

        if isinstance(controlfile, Control):
            # load model!
            self.__controlfile = controlfile
            self.parameters = self.__load_parameter_files()
            self.data = self.__load_data_files()

        else:
            # assume that controlfile must exist even if it is an empty document
            self.__controlfile = Control(open(controlfile))

    def set_header(self, header):
        if not header.endswith('\n'):
            header += '\n'
        self.__header = header

    @property
    def data_files(self):
        """
        Returns a list of the prms data files
        """
        if len(self.__data_files) < 1:
            try:
                if self.__controlfile.get_record('data_file')['nval'] == 1:
                    self.__data_files = [self.get_path(
                        self.__controlfile['data_file'])]
                else:
                    self.__data_files = [self.get_path(i) for i in
                                         self.__controlfile['data_file']]
            except KeyError:
                self.__data_files = []

        return self.__data_files

    @property
    def parameter_files(self):
        """
        Returns a list of the prms parameter files
        """
        if len(self.__parameter_files) < 1:
            try:
                if self.__controlfile.get_record('param_file')['nval'] == 1:
                    self.__parameter_files = [self.get_path(
                        self.__controlfile['param_file'])]
                else:
                    self.__parameter_files = [self.get_path(i) for i in
                                              self.__controlfile['param_file']]
            except KeyError:
                self.__parameter_files = []

        return self.__parameter_files

    def __load_data_files(self):
        """
        Convience method to load prms data files listed in the
        GSFLOW control file information. Creates and removes a temporary
        file in the GSFLOW ws directory to manage multiple datafiles

        Returns:
        -------
        <class 'prms_python.data.Data>
        """
        if len(self.data_files) < 1:
            warnings.warn("Control file does not have prms data" +
                          " files included, skipping pmrs data import")
            return

        else:
            data_file, self.__data_files_dict = \
                self.create_temp_prms_file(self.data_files)
            df = pp.Data(data_file)
            # os.remove(data_file)
            return df

    def __load_parameter_files(self):
        """
        Convience method to load prms parameter files listed in the
        GSFLOW control file information. Creates a temporary file in the
        GSFLOW ws directory.

        Returns:
        --------
        <class 'prms_python.parameters.Parameters'>
        """
        if len(self.parameter_files) < 1:
            warnings.warn("Control file does not have prms paramter" +
                          " files included, skipping pmrs parameter import")
            return

        else:
            param_file, self.__parameter_files_dict = \
                self.create_temp_prms_file(self.parameter_files)
            p = pp.Parameters(param_file)
            p.base_file_reader.close()
            # os.remove(param_file)
            return p

    def write(self, ws):
        """
        Write function that replaces the PRMS python write function
        Improvements allow for writing of multiple files based on input
        structure.
        Parameters:
        -----------
            ws (str): workspace for GSFlow model
        """
        super(PRMSModel, self).__init__(ws)
        self.__parameter_files = []

        fnum = 0
        fname = self.parameter_files[fnum]
        path = '\\'.join(fname.split('\\')[:-1])
        end_of_file = self.__parameter_files_dict[fname.split('\\')[-1]]

        if not os.path.exists(path):
            os.makedirs(path)

        params_file = open(fname, 'w')
        params_file.write(self.__header)
        params_file.write(self.__version)
        # begin writing model dimensions
        params_file.write("** Dimensions **\n")
        for key, val in self.parameters.dimensions.items():
            params_file.write("####\n")
            params_file.write("{}\n".format(key))
            params_file.write("{}\n".format(val))

        # begin writing model parameters
        params_file.write("** Parameters **\n")
        for d in self.parameters.base_params:
            params_file.write("####\n")
            params_file.write("{}\n".format(d['name']))
            params_file.write("{}\n".format(d['ndims']))
            for dimname in d['dimnames']:
                params_file.write("{}\n".format(dimname))
            params_file.write("{}\n".format(d["length"]))
            params_file.write("{}\n".format(d["vartype"]))

            try:
                for val in self.parameters.param_arrays[d['name']]:
                    if d['ndims'] == 2:
                        for v in val:
                            params_file.write("{}\n".format(v))
                    else:
                        params_file.write("{}\n".format(val))

            except KeyError:
                try:
                    for val in self.parameters[d['name']]:
                        if d['ndims'] == 2:
                            for v in val:
                                params_file.write("{}\n".format(v))
                        else:
                            params_file.write("{}\n".format(val))
                except TypeError:
                    params_file.write("{}\n".format(self.parameters[d['name']]))

            if d['name'] == end_of_file:
                params_file.close()
                fnum += 1
                try:
                    fname = self.parameter_files[fnum]
                    params_file = open(fname, "w")
                    end_of_file = self.__parameter_files_dict[
                        fname.split('\\')[-1]]
                except IndexError:
                    pass

        os.remove(self.parameters.base_file)

        self.__data_files = []
        fname = self.data_files[0]
        self.data.write(fname)
        os.remove(self.data.base_file)

    @staticmethod
    def load(controlfile, ws):
        """
        Method to load prms files from a GSFlow control file object

        Parameters:
        ----------
        controlfile: (object) <gsflow.Control> object
        """
        if isinstance(controlfile, str):
            controlfile = Control.load(controlfile)

        elif isinstance(controlfile, Control):
            pass

        else:
            raise TypeError("Controlfile is not of recognized type")

        return PRMSModel(controlfile, ws)

class GSFlowModel(ModelUtils):
    """
    Object to load, create, and write a full GSFLOW model. Utilizes
    functionality from Flopy 3.2.6 and prms_python.

    Parameters
    ----------
        controlfile: (str) GSFLOW controlfile name
        ws: (str) model workspace (path containing the GSFLOW controlfile)
    Methods
    -------
        load: Entry point to load an existing GSFLOW model

    Attributes:
    -----------

    """
    def __init__(self, controlfile, ws=None):

        self.__modflow_nam_file_path = None
        self.__parameter_files = []
        self.__parameter_files_dict = {}
        self.__data_files = []
        self.__config_files_dict = {}

        if ws is None:
            self.__ws = os.path.dirname(os.path.realpath(__file__))
        else:
            self.__ws = ws

        super(GSFlowModel, self).__init__(self.__ws)

        if isinstance(controlfile, Control):
            self.controlfile = controlfile
            self.name = controlfile.name
            self.modflow = self.__load_modflow_model()
            self.modflow_nam = ModFlowNam(self.modflow_nam_file_path)
            self.prms = self.__load_prms_model()

        elif isinstance(controlfile, str):

            self.name = os.path.join(self.__ws, controlfile)
            self.controlfile = Control.load(self.name)

    def __load_prms_model(self):
        prms = PRMSModel.load(self.controlfile, self.__ws)
        return prms

    def __load_modflow_model(self):
        """
        Convience method to load a modflow model from the GSFLOW control
        file information, reads a temporary modflow NAM file beacause of
        workspace conflicts with GSFlow and Flopy 3.2.6 assumptions

        Returns:
        --------
        <class 'flopy.modflow.mf.Modflow'> ie. a Flopy model object
        """
        if self.modflow_nam_file_path is None:
            warnings.warn("control file does not have modflow_name" +
                          " skipping modflow model import")
            return

        else:
            # Create a temporary name file with absolute name space in
            # the modflow directory and remove after model instance is created
            nam = self.create_temp_modflow_nam_file(self.modflow_nam_file_path)
            mf = flopy.modflow.Modflow.load(f=nam, model_ws=self.__ws,
                                            version="mfnwt")
            os.remove(os.path.join(self.__ws, nam))
            return mf

    @property
    def modflow_nam_file_path(self):
        """
        Returns the modflow NAM file path
        """
        if self.__modflow_nam_file_path is None:
            try:
                self.__modflow_nam_file_path = self.get_path(self.controlfile
                                                             ['modflow_name'])
            except KeyError:
                self.__modflow_nam_file_path = None

        return self.__modflow_nam_file_path

    @staticmethod
    def load(controlfile, ws=None):
        """
        Entry point to an existing GSFLOW control file
        Parameters:
        ----------
            controlfile: (str) GSFLOW control file name
            ws: (str) model workspace (path containing the GSFLOW controlfile)
        """
        controlfile = Control.load(os.path.join(ws, controlfile))
        return GSFlowModel(controlfile, ws=ws)

    def write(self, ws=None, controlfile=None, clear_relative_paths=False):
        """
        Method to write all configuration files for a complete GSFlow simulation
        and create output directories if they do not exist

        Parameters:
        -----------
            controlfile: (str) name of the control file if user wants to
                               change names... allows for multiple controlfiles
                               to be saved to the same workspace
            ws: (str) workspace aka. GSFlow model path
        """
        # todo: write output directories for model to run.
        if ws is None:
            ws = self.__ws
        else:
            self.__ws = ws
            self.__modflow_nam_file_path = None
            super(GSFlowModel, self).__init__(ws)

        modflow_ws, nam = self.split_path(self.modflow_nam_file_path)
        modflow_ws = self.get_path(modflow_ws)

        self.modflow.change_model_ws(modflow_ws)
        self.modflow.write_input()
        self.modflow_nam.write(modflow_ws,
                               clear_relative_paths=clear_relative_paths)
        self.prms.write(ws)

        control_ws, name = self.split_path(self.name)
        control_ws = os.path.join(ws, name)
        self.name = control_ws
        self.controlfile.write(control_ws)

        # build the output directory structure from the control file
        for key in self._output_keys:
            try:
                fpath = self.controlfile[key]
                path = self.split_path(fpath)[0]
                if len(path) > 0:
                    path = self.get_path(path)
                    if not os.path.exists(path):
                        os.makedirs(path)
            except KeyError:
                pass

        mfoutput = self.get_path(self.modflow_nam.gsflow_output_path)
        if not os.path.exists(mfoutput):
            os.makedirs(mfoutput)

    def run(self, controlfile=None, gsflow_exe='gsflow.exe'):
        """
        Method to run the GSFlow model contained in the GSFlowModel object

        Parameters:
        -----------
            gsflow_exe: (str) name and/or location of the gsflow.exe
        """
        from subprocess import Popen, PIPE
        warnings.warn('Please write GSFlowModel object prior to running edited instances of the model')

        if controlfile is None:
            controlfile = self.controlfile

        if isinstance(controlfile, file):
            controlfile = controlfile.name

        elif isinstance(controlfile, Control):
            controlfile = controlfile.name

        elif isinstance(controlfile, str):
            pass

        else:
            raise TypeError('Unrecognised type for controlfile')

        p = Popen([gsflow_exe, controlfile], stdout=PIPE,
                  stderr=PIPE, cwd=self.ws)
        while True:
            stdout_line = p.stdout.readline()
            c = stdout_line.decode('utf-8')
            if c != '':
                c = c.strip('\r\n')
                print('{}'.format(c))

        p.kill()
        return

class ModFlowNam(OrderedDict):
    """
    Class to read & write custom Gsflow based modflow nam files
    maintain old relative paths.

    Parameters
    ----------
        nam: (str, file) if nam is a string, it must be the absolute path
                         to the modflow name file. Can also be an open
                         modflow name file.
    """
    def __init__(self, nam):
        super(ModFlowNam, self).__init__()
        self.__input_path = ''
        self.__output_path = ''
        self.__header = '#Name file for GSFLOW MODFLOW-NWT model,' + \
                        ' generated by GSFloPy\n'
        self.spatial_reference = ''

        if isinstance(nam, file):
            self.__nam = nam.name.split('\\')[-1]
            self.__read_nam_file(nam)

        elif isinstance(nam, str):
            nam = nam.replace('/', '\\')
            self.__nam = nam.split('\\')[-1]
            if os.path.exists(nam):
                self.__read_nam_file(open(nam, 'r'))
            else:
                raise AssertionError('NAM file not found')
        else:
            raise TypeError('nam file not of recognized type <file> or <str>')

    def __read_nam_file(self, nam):
        """
        Method to read the modflow nam file and set its values to an
        ordered dictionary, maintains relative paths for operation with
        GSFlow model.

        Parameters:
        -----------
            name: (file) open modflow nam file
        """
        data = nam.readlines()
        for i, pkg in enumerate(data):
            if i <= 1 and pkg.startswith('#'):
                    if 'xul' in pkg:
                        self.spatial_reference = pkg

            else:
                pkg = [i for i in pkg.strip('\n').split(' ') if i != '']

                if len(pkg) > 3:
                    replace = pkg.pop(-1)
                else:
                    replace = ''

                path = pkg.pop(-1).split('\\')
                name = path.pop(-1)
                path = '\\'.join(path)
                unit = pkg[1]
                pkg = pkg[0]

                if pkg.lower() == 'dis':
                    self.__input_path = path

                elif pkg.lower() == 'list':
                    self.__output_path = path

                else:
                    pass

                rec = dict(name=name,
                           rel_path=path,
                           unit=unit,
                           pkg=pkg,
                           replace=replace)

                super(ModFlowNam, self).__setitem__(name, rec)

    def __check_if_input(self, pkg):
        """
        Checks if the pkg is considered input or output

        Parameters:
        -----------
            pkg: (str) the modflow namefile pakage name

        Returns:
        --------
            boolean
        """
        output = ('list', 'data', 'data(binary)')
        # input = ()
        if pkg.lower() in output:
            return False
        else:
            return True

    def __check_units(self, rec, mfnam):
        """
        Checks the flopy modflow produced nam file for potential unit conflicts,
        especially when mfuzf1 package is used:

        Parameters:
        -----------
            d (dict) this an mfnam record from the flopy temp nam file.
            mfnam <ModFlowNam object> corresponding to the flopy temp nam file

        Returns:
        --------
        bool
        """
        name = rec['name']
        unit = rec['unit']
        extension = name.split('.')[-1]

        if name in self:
            return True
        else:
            if extension.lower() in ('uzfbt1', 'uzfbt2'):
                for key, record in mfnam.items():
                    if record['name'].split('.')[-1].lower() == 'cbc':
                        if unit == record['unit']:
                            return False
                return True

            elif 'uzfb' in extension.lower():
                for key, record in self.items():
                    if unit == record['unit']:
                        return False
                return True

            else:
                return True

    def clear_path(self):
        """
        Removes the stored relative path from metadata for each pkg
        """
        for key, rec in self.items():
            rec['rel_path'] = ''

    def set_input_relative_path(self, path):
        """
        Sets a new relative path in for all input files

        Parameters:
        -----------
            path: (str) relative path name from input
        """
        path = path.replace('/', '\\')
        for key, rec in self.items():
            input = self.__check_if_input(rec['pkg'])
            if input:
                rec['rel_path'] = path
        self.__input_path = path

    def set_output_relative_path(self, path):
        """
        Sets a new relative path in for all output files

        Parameters:
        -----------
            path: (str) relative path name from input
        """
        path = path.replace('/', '\\')
        for key, rec in self.items():
            input = self.__check_if_input(rec['pkg'])
            if not input:
                rec['rel_path'] = path
        self.__output_path = path

    @property
    def gsflow_output_path(self):
        return self.__output_path

    @property
    def gsflow_input_path(self):
        return self.__input_path

    @staticmethod
    def load(nam):
        """
        Simple method to open a modflow name file and instantiate the
        ModFlowNam class

        Parameters:
        -----------
            nam: (str) name of the modflow nam file

        Returns:
            <class gsflow.ModFlowNam> object
        """
        nam = open(nam, 'r')
        return ModFlowNam(nam)

    def write(self, mf_ws, clear_relative_paths=False):
        """
        Read and replace the flopy nam file with a nam file
        that includes the necessary relative paths for GSFlow to
        operate correctly

        Parameters:
        -----------
            mf_ws: (str) workspace for modflow model
            clear_relative_paths: (bool) if True assumes mf_ws is the same as
                                        the GSFlow control file workspace
        """
        __mfnam = os.path.join(mf_ws, self.__nam)
        mfnam = ModFlowNam.load(__mfnam)

        f = open(__mfnam, 'w')
        f.write(self.__header)
        f.write(mfnam.spatial_reference)
        if clear_relative_paths:
            for key, rec in mfnam.items():
                f.write('{:14} {:4} {} {}\n'.format(rec['pkg'],
                                                    rec['unit'],
                                                    rec['name'],
                                                    rec['replace']))

        for key, rec in mfnam.items():
            if self.__check_units(rec, mfnam):
                if key in self:
                    rec['rel_path'] = self[key]['rel_path']

                else:
                    mfinput = self.__check_if_input(mfnam[key]['pkg'])
                    if mfinput:
                        rec['rel_path'] = self.__input_path
                    else:
                        rec['rel_path'] = self.__output_path

                if rec['rel_path'] == '':
                    f.write('{:14} {:4} {}{} {}\n'.format(rec['pkg'],
                                                          rec['unit'],
                                                          rec['rel_path'],
                                                          rec['name'],
                                                          rec['replace']))
                else:

                    f.write('{:14} {:4} {}\\{} {}\n'.format(rec['pkg'],
                                                            rec['unit'],
                                                            rec['rel_path'],
                                                            rec['name'],
                                                            rec['replace']))
            else:
                pass

model = 'gsflow.control'
ws = r'C:\Users\jlarsen\Desktop\RussianRiver\GSFLOW_1.2.1\data\sagehen\windows'
# ws = r'C:\Users\jlarsen\Desktop\RussianRiver\WriteTest\gsflow'
gsflow_exe = r'C:\Users\jlarsen\Desktop\RussianRiver\GSFLOW_1.2.1\bin\gsflow.exe'
gsflow = GSFlowModel.load(model, ws=ws)
print(gsflow.modflow.get_package_list())
dis = gsflow.modflow.get_package('UZF')

ws = r'C:\Users\jlarsen\Desktop\RussianRiver\WriteTest\gsflow'
gsflow.write(ws)
gsflow.run(gsflow_exe=gsflow_exe)

# todo: compile list of parameters that RedRiver group would like to change
# todo: add, subtract. Create methods for these.


#!/usr/bin/env python

# WS server example

import asyncio
import os
import websockets

async def echo(websocket, path):
    while True:
        msg = await websocket.recv()
        print(f'Received {len(msg)} bytes')
        await websocket.send(msg)

host = os.getenv('BIND_HOST', 'localhost')
print(f'Serving on {host}:8766')

start_server = websockets.serve(echo, host, 8766, max_size=2 ** 30)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()


#! /usr/bin/env python3

__all__ = [
    'FrameCorners',
    'CornerStorage',
    'build',
    'dump',
    'load',
    'draw',
    'without_short_tracks'
]

import click
import cv2
import numpy as np
import pims

from _corners import FrameCorners, CornerStorage, StorageImpl
from _corners import dump, load, draw, without_short_tracks, create_cli

class _CornerStorageBuilder:

    def __init__(self, progress_indicator=None):
        self._progress_indicator = progress_indicator
        self._corners = dict()

    def set_corners_at_frame(self, frame, corners):
        self._corners[frame] = corners
        if self._progress_indicator is not None:
            self._progress_indicator.update(1)

    def build_corner_storage(self):
        return StorageImpl(item[1] for item in sorted(self._corners.items()))

class Corners:
    MAX_ID = 0

    def __init__(self, coords, sizes, ids=None):
        if ids is None:
            ids = np.arange(Corners.MAX_ID, Corners.MAX_ID + sizes.size).astype(int)
            Corners.MAX_ID += sizes.size
        self.ids = np.reshape(ids, (-1))
        self.coords = np.reshape(coords, (-1, 2))
        self.sizes = np.reshape(sizes, (-1))
        self._sort_data()
    def filter(self, f):
        bools = []
        for i in range(self.ids.size):
            bools.append(bool(f(self.ids[i], self.coords[i], self.sizes[i])))
        bools = np.array(bools)
        return Corners(self.coords[bools == 1], self.sizes[bools == 1], self.ids[bools == 1])

    def merge(self, corners):
        def f(id, coords, size):
            return not np.any((np.sum((self.coords - coords - 0.0) ** 2, axis=1) <= (np.maximum(np.full_like(self.sizes, size), self.sizes) / 2) ** 2))
        corners = corners.filter(f)
        return Corners(np.concatenate((self.coords, corners.coords), axis=0),
                       np.concatenate((self.sizes, corners.sizes), axis=0),
                       np.concatenate((self.ids, corners.ids), axis=0))

    def to_frame_corners(self):
        return FrameCorners(self.ids.astype(int), self.coords, self.sizes)

    def rescale(self, coef):
        return Corners((self.coords*coef).astype(int), self.sizes*coef, self.ids)

    def _sort_data(self):
        sorting_idx = np.argsort(self.ids.flatten())
        self.ids = self.ids[sorting_idx].reshape(-1)
        self.coords = self.coords[sorting_idx].reshape(-1, 2)
        self.sizes = self.sizes[sorting_idx].reshape(-1)

def detect_new_corners(img, feature_params):
    corners = cv2.goodFeaturesToTrack(img, mask=None, **feature_params)
    return Corners(corners, np.full(corners.shape[0], feature_params.get("blockSize", 3)))

def detect_new_scaled_corners(img, scales, feature_params):
    result = Corners(np.array([]), np.array([]), np.array([]))
    params = dict(feature_params)

    for scale in scales:
        width = int(img.shape[1] * scale)
        height = int(img.shape[0] * scale)
        dim = (width, height)
        new_image = cv2.resize(img, dim, interpolation=cv2.INTER_AREA)
        result = result.merge(detect_new_corners(new_image, params).rescale(1 / scale))
    return result

def track_corners_lk(old_img, new_img, corners, lk_params):
    old_img = (old_img * 255).astype(np.uint8)
    new_img = (new_img * 255).astype(np.uint8)

    old_coords = np.reshape(corners.coords, (-1, 1, 2)).astype(np.float32)
    new_coords, status, _ = cv2.calcOpticalFlowPyrLK(old_img, new_img, old_coords, None, **lk_params)
    status = np.reshape(status, status.size)

    return Corners(new_coords[status==1], corners.sizes[status==1], corners.ids[status==1])

def _build_impl(frame_sequence: pims.FramesSequence,
                builder: _CornerStorageBuilder) -> None:
    feature_params = dict(maxCorners=1000,
                          qualityLevel=0.1,
                          minDistance=10,
                          blockSize=7)
    lk_params = dict(winSize=(25, 25),
                     maxLevel=3,
                     criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.02))

    old_img = frame_sequence[0]

    scales = [1., 0.75, 0.5, 0.25]

    corners = detect_new_scaled_corners(frame_sequence[0], scales , feature_params)
    builder.set_corners_at_frame(0, corners.to_frame_corners())

    for frame, img in enumerate(frame_sequence[1:], 1):
        corners = track_corners_lk(old_img, img, corners, lk_params)
        corners = corners.merge(detect_new_scaled_corners(img, scales, feature_params))
        builder.set_corners_at_frame(frame, corners.to_frame_corners())
        old_img = img

def build(frame_sequence: pims.FramesSequence,
          progress: bool = True) -> CornerStorage:
    """
    Build corners for all frames of a frame sequence.

    :param frame_sequence: grayscale float32 frame sequenc
    :param progress: enable/disable building progress bar.
    :return: corners for all frames of given sequence.
    """
    if progress:
        with click.progressbar(length=len(frame_sequence),
                               label='Calculating corners') as progress_bar:
            builder = _CornerStorageBuilder(progress_bar)
            _build_impl(frame_sequence, builder)
    else:
        builder = _CornerStorageBuilder()
        _build_impl(frame_sequence, builder)
    return without_short_tracks(builder.build_corner_storage(), 5)

if __name__ == '__main__':
    create_cli(build)()  # pylint:disable=no-value-for-parameter


def solution(n, lost, reserve):
    # 1. set을 만든다. (전처리를 하여 2번에서 연산을 단순하게 하였다)
    reserve_only = set(reserve) - set(lost) # 진짜 체육복을 빌려줄 수 있는 학생들만 남음
    lost_only = set(lost) - set(reserve)    # 진짜 체육복을 빌려야 하는 학생들만 남음

    # 2. 여분을 기준으로 앞뒤를 확인하여 체육복을 빌려준다.
    for reserve in reserve_only:
        front = reserve - 1
        back = reserve + 1
        if front in lost_only: # 있다면 빌려줄 수 있으므로 lost_only에서 삭제함.
            lost_only.remove(front)
        elif back in lost_only:
            lost_only.remove(back)

    # 3. 전체 학생 수에 lost_only에 남은 학생 수를 빼준다.
    return n - len(lost_only)

n = 5

lost = [2, 4]

reserve = [1,3,5]

print(solution(n, lost, reserve)) # 5

프로그래머스/Level1/체육복/프로그래머스_체육복_Set.py

프로그래머스_체육복_Set.py


# -*- coding: utf-8 -*-
"""
Created on Thu Dec 26 20:05:23 2019

@author: 王新华
"""

import numpy as np
from astropy.io import fits
import scipy.fftpack as fft
import cupy as cp
from xyy_lib import xyy_lib as xyy
import os
from skimage import filters
import json
import re
import matplotlib.pyplot as plt

def align():
    f = open(r"/home/wangxinhua/level1/Level1/json.txt",'r')
    para = json.load(f)
    f.close()
    rcxsize = int(para['rcxsize'])
    rcysize = int(para['rcysize'])
    corstart = re.findall('\d+',para['corstart'])
    corstart = [int(i) for i in corstart]
    corsize = re.findall('\d+',para['corsize'])
    corsize = [int(i) for i in corsize]
    flated_path = para['flated_path']
    sobel = int(para['sobel'])
    path = para['path']
    only_align_no_luckyimage = int(para['only_align_no_luckyimage'])
    redrive = para['redrive']
    only_align_no_luckyimage_path = para['only_align_no_luckyimage_path']
    pfstart = re.findall('\d+',para['pfstart'])
    pfstart = [int(i) for i in pfstart]
    pfsize = re.findall('\d+',para['pfsize'])
    pfsize = [int(i) for i in pfsize]
    lucky_align_path = para['lucky_align_path']
    win=xyy.win(int(pfsize[0]),int(pfsize[1]),0.5,winsty='hann')     #----窗函数
    diameter = float(para['diameter'])
    wavelen = float(para['wavelen'])
    pixsca = float(para['pixsca'])
    fsp = float(para['fsp'])
    srstx = int(para['srstx'])
    srsty = int(para['srsty'])
    srxsize = int(para['srxsize'])
    srysize = int(para['srysize'])
    postprocess_flag = int(para['postprocess_flag'])
    srsize = int(para['srsize'])
    winsr=xyy.win(srsize,srsize, 0.5, winsty='hann')
    diaratio = float(para['diaratio'])
    start_r0 = float(para['start_r0'])
    step_r0 = float(para['step_r0'])
    maxfre=wavelen*10.0**(-10.0)/(2.0*diameter*pixsca)*(180.0*3600.0/np.pi)
    filename = para['filename']
    sitfdata=fits.getdata(filename)
    gussf=xyy.gaussf2d(rcxsize,rcysize,1.5)
    infrq=(pfsize[0]//2)*0.05/maxfre
    otfrq=(pfsize[0]//2)*0.10/maxfre
    datapath=[]
    flatpath=[]
    darkpath=[]
    subpaths = os.listdir(path)
    for i in range(len(subpaths)):
        subpath=os.path.join(path,subpaths[i])

        if ('F' in subpaths[i]) or ('f' in subpaths[i]) :
            flatpath.append(subpath)
        elif ('D' in subpaths[i]) or ('d' in subpaths[i]):
            darkpath.append(subpath)
        else:
            datapath.append(subpath)

    #做对齐
    #读预处理后的数据做对齐
    proceed_path = r'F:/2019-12-29chengjiang/20190518/HA'
    dirs = xyy.nvst_dirsandfiles_path(proceed_path)
    roots = dirs[0]
    fitsfile = dirs[1]
    t = 0
    for i in roots:
        i = i.split(':')[1]
        if 'f' not in i and 'd' not in i and 'F' not in i and 'D' not in i:
            data_root = i
            data_fits = dirs[1][t]
        t+=1
    for i in data_fits:
        data_path_fits = os.listdir(i)
        numb = len(data_path_fits)
        assert numb == 100
        cube = np.empty([numb,rcxsize,rcysize], dtype = np.float32)
        try:
            data_dir_fitstmp = os.path.join(i,data_path_fits[0])
        except Exception as e:
            print('warning:目录'+i+'下没有fits文件')
            continue
        ini = xyy.readfits(data_dir_fitstmp)[0]
        initmp = ini[corstart[0]:corstart[0]+corsize[0],corstart[1]:corstart[1]+corsize[1]]
        initmp_gpu = cp.asarray(initmp)
        print('基准文件：'+ data_dir_fitstmp)
        if sobel == 1:
            initmp = filters.sobel(filters.gaussian(initmp,5.0))
        t = 0
        for j in data_path_fits:
            head=fits.getheader(os.path.join(i,j))
            if t !=0:
                data = xyy.readfits(i+"\\"+j)[0]
                datatmp = data[corstart[0]:corstart[0]+corsize[0],corstart[1]:corstart[1]+corsize[1]]
                if sobel == 1:
                    datatmp = filters.sobel(filters.gaussian(datatmp,5.0))
                datatmp_gpu = cp.asarray(datatmp)
                cc,corr = xyy.corrmaxloc_gpu(initmp_gpu,datatmp_gpu)
                tmp = xyy.imgshift(data,[-cc[0],-cc[1]])#对齐后的图
                if only_align_no_luckyimage == 1:
                    #不选帧，直接叠加
                    print('不选帧对齐模式')
                    ini += tmp
                else:
                    #print('选帧后对齐模式')
                    cube[t,:,:] = tmp[0:rcxsize,0:rcysize]
                    cubepf=cube[:,pfstart[0]:pfstart[0]+pfsize[0],pfstart[1]:pfstart[1]+pfsize[1]]
                    cubemean=np.mean(cubepf, axis=0)
                    psdcube = np.empty([numb,pfsize[0],pfsize[1]], dtype=np.float32)

                    for nn in range(numb):
                        tmp=cubepf[nn,:,:].copy()
                        meantmp=np.mean(tmp)
                        tmp=(tmp-meantmp)*win+meantmp
                        psd=np.abs(fft.fftshift(fft.fft2(tmp)))**2
                        psd=(psd/psd[pfsize[0]//2,pfsize[1]//2]).astype(np.float32)
                        psdcube[nn,:,:]=psd
                    psdmean=np.mean(psdcube, axis=0)
                    psdcube=psdcube/psdmean
                    [Y,X]=np.meshgrid(np.arange(pfsize[1]),np.arange(pfsize[0]))
                    dist=((X-pfsize[0]//2)**2.0+(Y-pfsize[1]//2)**2.0)**0.5
                    ring=np.where((dist>=infrq)&(dist<=otfrq), 1.0, 0.0).astype(np.float32)
                    psdcube=psdcube*ring
                    ringcube=np.mean(np.mean(psdcube, axis=1),axis=1)
                    index0=np.argsort(ringcube)[::-1]
                    #---------------------------------------------------------------------------------------
                    #--------------------------------  取排序前**帧, 再次相关对齐，叠加
                    cubesort0=cube.copy()[index0][0:int(fsp*numb),:,:]
                    ini=np.mean(cubesort0, axis=0).astype(np.float32)
                    initmp=ini[corstart[0]:corstart[0]+corsize[0],corstart[1]:corstart[1]+corsize[1]]
                    if sobel==1:
                        initmp=filters.sobel(filters.gaussian(initmp,5.0))
                    initmp_gpu=cp.asarray(initmp)
                    # ----------------------   对齐
                    for nn in range(cubesort0.shape[0]):
                        data=cubesort0[nn,:,:].copy()
                        datatmp=data[corstart[0]:corstart[0]+corsize[0],corstart[1]:corstart[1]+corsize[1]]
                        if sobel==1:
                            datatmp=filters.sobel(filters.gaussian(datatmp,5.0))

                        datatmp_gpu=cp.asarray(datatmp)
                        cc,corr=xyy.corrmaxloc_gpu(initmp_gpu, datatmp_gpu)

                        ####cc,corr=xyy.corrmaxloc(initmp, datatmp)

                        tmp=xyy.imgshift(data,[-cc[0],-cc[1]])
                        cubesort0[nn,:,:]=tmp

                    averg=np.mean(cubesort0, axis=0).astype(np.float32)#叠加

            t +=1
        #----------------------------    选帧（1计算功率谱，2环带积分，3排序）

        #.................................................
        aligned_path = i+'/aligned'
        print('对齐后文件存储位置：'+path+os.path.splitdrive(aligned_path)[1])
        if only_align_no_luckyimage == 1:
            try:
                os.mkdir(path+os.path.splitdrive(aligned_path)[1])
            except Exception as e:
                print('警告：'+aligned_path+'文件夹已经存在')
            xyy.writefits(path+os.path.splitdrive(aligned_path)[1]+'\\'+'aligned.fits',initmp/len(data_path_fits))
        else:
            try:
                os.mkdir(path+os.path.splitdrive(aligned_path)[1])
            except Exception as e:
                print(path+aligned_path+'文件夹已经存在')

            xyy.writefits(path+os.path.splitdrive(aligned_path)[1]+'\\'+'aligned.fits',averg)
        #退卷积
        if postprocess_flag == 1:
            cubesr=cube[:,srstx:srstx+srxsize,srsty:srsty+srysize]
            r0,index=xyy.cubesrdevr0(cubesr,srsize,winsr,sitfdata,diameter,diaratio,maxfre,0.00,0.06,start_r0,step_r0)
            sitf=xyy.GetSitf(sitfdata,maxfre,rcxsize,index)
            img=xyy.ImgPSDdeconv(averg,sitf)

            head['CODE2'] = r0

            result=xyy.ImgFilted(img,gussf)

            result=result/np.median(result)*np.median(averg)
            fitsname = path+os.path.splitdrive(aligned_path)[1]+'\\'+'post_aligned.fits'
            xyy.writefits(fitsname,result.astype(np.float32),head)
            #plt.imshow(result)

if __name__ == "__main__":
    align()


#Move Zeros [72ms]
class Solution(object):
    def moveZeroes(self, nums):
        index = length = len(nums)
        i = 0
        while i < index:
            if nums[i] == 0:
                del nums[i]
                index -= 1
            else:
                i += 1
        for i in range(length-index):
            nums.append(0)


try:
    sys.path.remove('/opt/ros/kinetic/lib/python2.7/dist-packages')
except:
    pass

import cv2
import numpy as np
cap = cv2.VideoCapture("/home/abhinav/Desktop/ENPM673/Project2/data/project_video.mp4")

global templ
global tempr
templ = 0
tempr = 0

def window_centers(image,out,window_width,window_height,margin,dst):#templ,tempr):
    left_windows=[]
    right_windows =[]
    w = image.shape[1]
    h = image.shape[0]
    mid = np.int((dst[0][0]+dst[1][0])/2)#np.int(w/2)#

    windows = int(h/window_height)
    upper = int(windows/2) +5
    leftHist = np.sum(image[:int(h-upper),:mid],axis=0)
    rightHist = np.sum(image[:int(h-upper),mid:],axis=0)
    cv2.imshow('d',image[:int(h-upper),:mid])
    print(rightHist)

    window = np.ones(window_width)
    left = np.argmax(np.convolve(window,leftHist))-int(window_width/2)
    right = np.argmax(np.convolve(window,rightHist))-int(window_width/2) +mid
    left_windows.append(left)
    right_windows.append(right)

    print(right)

    #Search for nonzero pixels in each window
    global templ
    global tempr

    for win in range(0,upper):
        level = np.sum(image[(h - (win+1)*window_height):(h - (win)*window_height),:],axis=0)
        conv = np.convolve(window,level)

        x_leftMin = int(max((left-margin+window_width/2),0))
        x_leftMax = int(min((left+margin+window_width/2),mid))
        if (np.argmax(conv[x_leftMin:x_leftMax]) > 0):
            l_center = np.argmax(conv[x_leftMin:x_leftMax])+int(x_leftMin-window_width/2)
            templ = np.argmax(conv[x_leftMin:x_leftMax])
        else:
            l_center = templ + int(x_leftMin-window_width/2)
        print(np.argmax(conv[x_leftMin:x_leftMax]))

        x_rightMin = int(max((right-margin+window_width/2),mid))
        x_rightMax = int(min((right+margin+window_width/2),w))
        if (np.argmax(conv[x_rightMin:x_rightMax]) > 0):
            r_center = np.argmax(conv[x_rightMin:x_rightMax])+int(x_rightMin-window_width/2)
            tempr = np.argmax(conv[x_rightMin:x_rightMax])
        else:
            r_center = tempr + int(x_rightMin-window_width/2)
            # continue

        y_min = h - (win+1)*window_height
        y_max = h - (win)*window_height

        cv2.rectangle(out,(int(l_center),y_min),(int(l_center+window_width),y_max),(0,255,255),2)
        cv2.rectangle(out,(int(r_center),y_min),(int(r_center+window_width),y_max),(255,0,255),2)

        left_windows.append(l_center)
        right_windows.append(r_center)
    # left_inds=[]
    left_inds = left_windows#np.average(left_windows[-15:],axis=0)
    # right_inds=[]
    right_inds = right_windows#np.average(right_windows[-15:],axis=0)

    return out,left_inds,right_inds#,templ,tempr

K = np.array([[  1.15422732e+03,0.00000000e+00,6.71627794e+02],
              [  0.00000000e+00,1.14818221e+03,3.86046312e+02],
              [  0.00000000e+00,0.00000000e+00,1.00000000e+00]])
dist = np.array([ -2.42565104e-01,-4.77893070e-02,  -1.31388084e-03,  -8.79107779e-05,
    2.20573263e-02])
def window_mask(width, height, img_ref, center, level):
    output = np.zeros_like(img_ref)
    output[int(img_ref.shape[0]-(level+1)*height):int(img_ref.shape[0]-level*height), max(0,int(center-width)):min(int(center+width),img_ref.shape[1])] = 1
    return output
def adjust_gamma(image, gamma=1.0):
	# build a lookup table mapping the pixel values [0, 255] to
	# their adjusted gamma values
    lookUpTable = np.empty((1,256), np.uint8)
    for i in range(256):
        lookUpTable[0,i] = np.clip(pow(i / 255.0, gamma) * 255.0, 0, 255)
    res = cv2.LUT(image, lookUpTable)
    return res
def preprocessing(frame):
    th = np.median(frame[int(frame.shape[0]/2):,:,:])
#     frame = adjust_gamma(frame,gamma=1.5)
#     undist = cv2.undistort(frame,K,dist)
#     blur = cv2.bilateralFilter(undist,9,75,75)
#     median = cv2.medianBlur(blur,5)

#     gray = cv2.cvtColor(median, cv2.COLOR_BGR2HLS)
#     s_channel = gray[:,:,2]
#     l_channel = gray[:,:,1]

    #Create mask for S Channel
    if th<60:
        s_channel = adjust_gamma(frame,gamma=25.0)
        undist = cv2.undistort(frame,K,dist)
        blur = cv2.bilateralFilter(undist,9,75,75)
        median = cv2.medianBlur(blur,5)

        gray = cv2.cvtColor(median, cv2.COLOR_RGB2LAB)
        s_channel = gray[:,:,2]
        s_channel = cv2.Sobel(s_channel,cv2.CV_64F,1,0)
        s_channel = np.absolute(s_channel)
        s_channel = np.uint8(255*s_channel/np.max(s_channel))
        l_channel = gray[:,:,0]
        s_min = 40
        s_max = 250

        l_min = 170
        l_max = 255

        mask1 = np.zeros([s_channel.shape[0],s_channel.shape[1]])
        mask1[(s_channel>=s_min)&(s_channel<=s_max)]=1

        mask2 = np.zeros([l_channel.shape[0],l_channel.shape[1]])
        mask2[(l_channel>=l_min)&(l_channel<=l_max)]=1

    elif th>130:
        s_channel = adjust_gamma(frame,gamma=1)
        undist = cv2.undistort(frame,K,dist)
        blur = cv2.bilateralFilter(undist,9,75,75)
        median = cv2.medianBlur(blur,5)

        gray = cv2.cvtColor(median, cv2.COLOR_BGR2LAB)
        s_channel = gray[:,:,2]
        s_channel = gray[:,:,2]
        s_channel = cv2.Sobel(s_channel,cv2.CV_64F,1,0)
        s_channel = np.absolute(s_channel)
        s_channel = np.uint8(255*s_channel/np.max(s_channel))
        l_channel = gray[:,:,0]
        s_min = 20
        s_max = 250

        l_min = 220
        l_max = 255

        mask1 = np.zeros([s_channel.shape[0],s_channel.shape[1]])
        mask1[(s_channel>=s_min)&(s_channel[1]<=s_max)]=1

        mask2 = np.zeros([l_channel.shape[0],l_channel.shape[1]])
        mask2[(l_channel>=l_min)&(l_channel<=l_max)]=1
    else:
        s_channel = adjust_gamma(frame,gamma=1.5)
        undist = cv2.undistort(frame,K,dist)
        blur = cv2.bilateralFilter(undist,9,75,75)
        median = cv2.medianBlur(blur,5)

        gray = cv2.cvtColor(median, cv2.COLOR_BGR2LAB)
        s_channel = gray[:,:,2]
        s_channel = cv2.Sobel(s_channel,cv2.CV_64F,1,0)
        s_channel = np.absolute(s_channel)
        s_channel = np.uint8(255*s_channel/np.max(s_channel))
        # s_channel = cv2.Canny(s_channel,10,300)
        l_channel = gray[:,:,0]
        s_min = 25
        s_max = 250

        l_min = 190
        l_max = 255

        mask1 = np.zeros([s_channel.shape[0],s_channel.shape[1]])
        mask1[(s_channel>=s_min)&(s_channel[1]<=s_max)]=1

        mask2 = np.zeros([l_channel.shape[0],l_channel.shape[1]])
        mask2[(l_channel>=l_min)&(l_channel<=l_max)]=1

    combined = np.zeros([frame.shape[0],frame.shape[1]])
    combined[(mask1==1)|(mask2==1)]=1
    mask = np.uint8(255*combined/np.max(combined))
#     mask = cv2.inRange(median,np.array([0,190,80]),np.array([255,255,150]))
    seg = cv2.bitwise_and(frame,median,mask=mask)
    return seg,combined,th

while(True):
    ret,frame = cap.read()

    seg,combined,th = preprocessing(frame)
    #Extract the region of interest and warp to get bird's eye view
    h = frame.shape[0]
    w = frame.shape[1]
#     src = np.float32([[w-(0.5-0.08/2),h*0.62],[w*(0.5+0.08/2),h*0.62],[w*(0.5+0.76/2),h*0.935],[w*(0.5-0.76/2),h*0.935]])
#     dst = np.array([[0,0],[400,0],[400,600],[0,400]])
    src = np.array([[375,480],[905,480],[1811,685],[-531,685]])#np.array([[375,480],[905,480],[1811,685],[-531,685]])#np.array([[600,500],[770,500],[1050,680],[350,680]])#
#     dst = np.float32([[w*0.25,0],[0.75*w,0],[0.75*w,h],[0.25*w,h]])
#     src = np.array([[580,450],[160,h],[1150,h],[740,450]])
    dst = np.array([[100,0],[w,0],[w,h-100],[100,h-100]])#np.array([[300,300],[500,300],[500,600],[300,600]])#
    H,flag = cv2.findHomography(src,dst)
    Hinv,flag = cv2.findHomography(dst,src)
    out= cv2.warpPerspective(seg,H,(w,h-100))
    out2 = cv2.Canny(seg,0,300)
    out3 = cv2.warpPerspective(out2,H,(w,h-100))
    out_gray = cv2.cvtColor(out,cv2.COLOR_BGR2GRAY)
    ret,thresh1 = cv2.threshold(out_gray,100,255,cv2.THRESH_BINARY)

#     font = cv2.FONT_HERSHEY_SIMPLEX
#     cv2.putText(out,str(th),(10,500), font, 4,(255,0,0),2,cv2.LINE_AA)
# #     cv2.putText(l_channel,str(th),(10,500), font, 4,(255,0,0),2,cv2.LINE_AA)
#     cv2.putText(combined,str(th),(10,500), font, 4,(255,0,0),2,cv2.LINE_AA)
    ###########################################

#     window_width = 20
#     window_height = 50
#     curve_centers = tracker(Mywindow_width=window_width, Mywindow_height=window_height, Mymargin = 25, My_ym = 10/720, My_xm = 4/384, Mysmooth_factor=15)
#     window_centroids = curve_centers.find_window_centroids(thresh1)
#     # Points used to draw all the left and right windows
#     l_points = np.zeros([thresh1.shape[0],thresh1.shape[1]])
#     r_points = np.zeros([thresh1.shape[0],thresh1.shape[1]])

#     # points used to find the right & left lanes
#     rightx = []
#     leftx = []

#     # Go through each level and draw the windows
#     for level in range(0,len(window_centroids)/2):
#         # Window_mask is a function to draw window areas
#         # Add center value found in frame to the list of lane points per left, right
#         leftx.append(window_centroids[level][0])
#         rightx.append(window_centroids[level][1])

#         l_mask = window_mask(window_width,window_height,thresh1,window_centroids[level][0],level)
#         r_mask = window_mask(window_width,window_height,thresh1,window_centroids[level][1],level)
#         # Add graphic points from window mask here to total pixels found
#         l_points[(l_points == 255) | ((l_mask == 1) ) ] = 255
#         r_points[(r_points == 255) | ((r_mask == 1) ) ] = 255

#     # Draw the results
#     template = np.array(r_points+l_points,np.uint8) # add both left and right window pixels together
#     zero_channel = np.zeros_like(template) # create a zero color channel
#     template = np.array(cv2.merge((zero_channel,template,zero_channel)),np.uint8) # make window pixels green
#     warpage = np.array(cv2.merge((thresh1,thresh1,thresh1)),np.uint8) # making the original road pixels 3 color channels
#     result = cv2.addWeighted(warpage, 1, template, 0.5, 0.0) # overlay the original road image with window results
    result,leftx,rightx = window_centers(thresh1,out,window_width=50,window_height=10,margin=25,dst=dst)

    # print(rightx)
    window_height = 20
    window_width=50
    res_yvals = np.int32(thresh1.shape[0]-np.arange(len(leftx))*window_height)

    # left_lane = np.hstack

    # p = np.polyfit()
    yvals = np.arange(0,thresh1.shape[0])
    # print(yvals)

    degree = 2
    print('l',leftx)
    print('r',rightx)
    left_fit = np.polyfit(res_yvals, leftx, degree)
    left_fitx = np.zeros(yvals.shape)
    for i in range(degree+1):
        left_fitx = left_fitx + left_fit[i]*(np.power(yvals,(degree-i)))
    left_fitx = np.array(left_fitx,np.int32)

    right_fit = np.polyfit(res_yvals, rightx, degree)
    right_fitx = np.zeros(yvals.shape)
    for i in range(degree+1):
        right_fitx = right_fitx + right_fit[i]*(np.power(yvals,(degree-i)))
    right_fitx = np.array(right_fitx,np.int32)

    left_lane = np.array(list(zip(np.concatenate((left_fitx-window_width/2, left_fitx[::-1]+window_width/2),axis=0),np.concatenate((yvals,yvals[::-1]),axis=0))),np.int32)
    right_lane = np.array(list(zip(np.concatenate((right_fitx-window_width/2, right_fitx[::-1]+window_width/2),axis=0),np.concatenate((yvals,yvals[::-1]),axis=0))),np.int32)

    road = np.zeros_like(frame)
    road_bkg = np.zeros_like(frame)
    cv2.fillPoly(road,[left_lane],color=[255,0,0])
    cv2.fillPoly(road,[right_lane],color=[0,0,255])
    cv2.fillPoly(road_bkg,[left_lane],color=[255,255,255])
    cv2.fillPoly(road_bkg,[right_lane],color=[255,255,255])

    img_size = (frame.shape[1],frame.shape[0])

    road_warped = cv2.warpPerspective(road,Hinv,img_size,flags=cv2.INTER_LINEAR)
    road_warped_bkg= cv2.warpPerspective(road_bkg,Hinv,img_size,flags=cv2.INTER_LINEAR)

    base = cv2.addWeighted(frame,1.0,road_warped, -1.0, 0.0)
    result2 = cv2.addWeighted(base,1.0,road_warped, 1.0, 0.0)

    ym_per_pix = 10/720
    xm_per_pix = 4/384

    curve_fit_cr = np.polyfit(np.array(res_yvals,np.float32)*ym_per_pix,np.array(leftx,np.float32)*xm_per_pix,2)
    curverad = ((1 + (2*curve_fit_cr[0]*yvals[-1]*ym_per_pix + curve_fit_cr[1])**2)**1.5) /np.absolute(2*curve_fit_cr[0])#curverad = ((1 + (2*left_fit[0]*yvals[-1] + left_fit[1])**2)**1.5) /np.absolute(2*left_fit[0])

    # Calculate the offset of the car on the road
    camera_center = (left_fitx[-1] + right_fitx[-1])/2
    center_diff = (camera_center-out.shape[1]/2)*xm_per_pix
    side_pos = 'left'
    if center_diff <= 0:
        side_pos = 'right'
    print(curverad)

    # Visualize the results of identified lane lines and overlapping them on to the original undistorted image
    # plt.figure(figsize = (30,20))
    # grid = gridspec.GridSpec(8,2)
    # # set the spacing between axes.
    # grid.update(wspace=0.05, hspace=0.05)
    # gidx=0
    # #img_plt = plt.subplot(grid[0])
    # plt.subplot(grid[gidx])
    cv2.imshow('road',out3)
    # plt.title('Identified lane lines')

    #img_plt = plt.subplot(grid[1])
    # plt.subplot(grid[gidx+1])
    cv2.imshow('result',result)
    # plt.title('Lane lines overlapped on original image')

    # plt.show()

    cv2.imshow('s',result2)
    cv2.imshow('l',thresh1)
#     cv2.imshow('test',l_channel)
#     cv2.imshow('mask',mask)
    while(True):
        if cv2.waitKey(1)& 0xff==ord('q'):
            break
    if cv2.waitKey(1)& 0xff==ord('q'):
        cv2.destroyAllWindows()
        break


# -*- coding: utf-8 -*-
"""
Created on Tue May  7 18:07:06 2019

@author: kaany
"""
from sklearn.decomposition import PCA
from matplotlib import pyplot as plt
import numpy as np

from DataGenerator import generateData
from Preprocessing import deleteFeaturesRandomly

NUMBER_OF_CLASSES = 4
NUMBER_OF_FEATURES = NUMBER_OF_CLASSES*2
NUMBER_OF_FEATURES_PER_CLASS = 200
TOTAL_NUMBER_OF_RECORDS = NUMBER_OF_CLASSES * NUMBER_OF_FEATURES_PER_CLASS

FEATURE_MEAN_RANGE = [0, 50]

RANDOM_NUMBER_SEED = 0
NUMBER_OF_FEATURES_TO_PRUNE = 4

data, labels = generateData(NUMBER_OF_CLASSES, NUMBER_OF_FEATURES,
                            NUMBER_OF_FEATURES_PER_CLASS, FEATURE_MEAN_RANGE,
                            RANDOM_NUMBER_SEED)
prunedData = deleteFeaturesRandomly(data, labels, NUMBER_OF_FEATURES_TO_PRUNE,
                                    randomNumberSeed=RANDOM_NUMBER_SEED)

distinctLabels = np.unique(labels)

pca = PCA()
pcaData = pca.fit_transform(prunedData)

plt.figure()
plt.title("Feature Selection With PCA")
plt.xlabel("PC1")
plt.ylabel("PC2")
for label in distinctLabels:
    plt.scatter(pcaData[labels==label,0], pcaData[labels==label,1],
                c=np.random.rand(3,))


from __future__ import unicode_literals, print_function
import os.path
from contextlib import contextmanager
import fabric.api as fappy
from fabric.contrib import django, console

TEST_HOST = ""
fappy.env.hosts_config = {TEST_HOST: {'src_dir': '$HOME/web/vikasa/src',
                                      'env_dir': '$HOME/web/vikasa/env'}}
fappy.env.hosts = []

@contextmanager
def virtualenv(host=None):
    host = fappy.env.host_string if host is None else host
    venv = fappy.env.hosts_config[host]['env_dir']
    src = fappy.env.hosts_config[host]['src_dir']
    env_vars = {'DJANGO_SETTINGS_MODULE': 'project.settings',
                'VIRTUAL_ENV': venv}
    env_bin = os.path.join(venv, 'bin')
    with \
            fappy.path(env_bin, behavior='prepend'), \
            fappy.shell_env(**env_vars), \
            fappy.cd(src):
        yield env_bin, env_vars, src

@fappy.task
def print_models_local():
    django.settings_module('vikasa.settings')
    from django.db.models import get_models
    for model in get_models():
        print(model)

@fappy.task
def print_models():
    with virtualenv():
        fappy.run('fab print_models_local')

@fappy.task
def restart():
    fappy.run("pkill -HUP -u {user} uwsgi".format(user=fappy.env.user))

@fappy.task
def test():
    with virtualenv():
        fappy.run("python -Wignore manage.py test")

@fappy.task
def deploy():
    with virtualenv():
        fappy.run("git pull --ff-only")
        with fappy.settings(warn_only=True):
            fappy.run("pip install -r requirements.txt")
        fappy.run("python manage.py migrate --noinput")
        fappy.run("python manage.py collectstatic --noinput")
        restart()

@fappy.task
def clean():
    with virtualenv():
        fappy.run("git clean --dry-run")
        if console.confirm("Proceed?"):
            fappy.run("git clean --force")

@fappy.task
def shell():
    with virtualenv() as (env_bin, env_vars, src):
        env_vars['TERM'] = 'screen'
        env_vars['PATH'] = '{env_bin}:$PATH'.format(env_bin=env_bin)
        command = " ".join(['cd "{src}" &&'.format(src=src),
                            '/usr/bin/env',
                            '--unset=PYTHONHOME'] +
                           ['{}="{}"'.format(key, env_vars[key])
                            for key in env_vars] +
                           ['$SHELL'])
        fappy.open_shell(command)

@fappy.task
def create_settings(target='vikasa/settings_local.py', **kwargs):
    template = open('vikasa/settings.py.template', 'r').read()
    content = template % kwargs
    open(target, 'w+').write(content)


import torch
import torch.nn as nn
import torch.nn.functional as F

from kornia.filters.kernels import get_spatial_gradient_kernel2d, get_spatial_gradient_kernel3d, normalize_kernel2d

def spatial_gradient(input: torch.Tensor, mode: str = 'sobel', order: int = 1, normalized: bool = True) -> torch.Tensor:
    r"""Computes the first order image derivative in both x and y using a Sobel
    operator.

    .. image:: _static/img/spatial_gradient.png

    Args:
        input: input image tensor with shape :math:`(B, C, H, W)`.
        mode: derivatives modality, can be: `sobel` or `diff`.
        order: the order of the derivatives.
        normalized: whether the output is normalized.

    Return:
        the derivatives of the input feature map. with shape :math:`(B, C, 2, H, W)`.

    Examples:
        >>> input = torch.rand(1, 3, 4, 4)
        >>> output = spatial_gradient(input)  # 1x3x2x4x4
        >>> output.shape
        torch.Size([1, 3, 2, 4, 4])
    """
    if not isinstance(input, torch.Tensor):
        raise TypeError("Input type is not a torch.Tensor. Got {}".format(type(input)))

    if not len(input.shape) == 4:
        raise ValueError("Invalid input shape, we expect BxCxHxW. Got: {}".format(input.shape))
    # allocate kernel
    kernel: torch.Tensor = get_spatial_gradient_kernel2d(mode, order)
    if normalized:
        kernel = normalize_kernel2d(kernel)

    # prepare kernel
    b, c, h, w = input.shape
    tmp_kernel: torch.Tensor = kernel.to(input).detach()
    tmp_kernel = tmp_kernel.unsqueeze(1).unsqueeze(1)

    # convolve input tensor with sobel kernel
    kernel_flip: torch.Tensor = tmp_kernel.flip(-3)

    # Pad with "replicate for spatial dims, but with zeros for channel
    spatial_pad = [kernel.size(1) // 2, kernel.size(1) // 2, kernel.size(2) // 2, kernel.size(2) // 2]
    out_channels: int = 3 if order == 2 else 2
    padded_inp: torch.Tensor = F.pad(input.reshape(b * c, 1, h, w), spatial_pad, 'replicate')[:, :, None]

    return F.conv3d(padded_inp, kernel_flip, padding=0).view(b, c, out_channels, h, w)

def spatial_gradient3d(input: torch.Tensor, mode: str = 'diff', order: int = 1) -> torch.Tensor:
    r"""Computes the first and second order volume derivative in x, y and d using a diff
    operator.

    Args:
        input: input features tensor with shape :math:`(B, C, D, H, W)`.
        mode: derivatives modality, can be: `sobel` or `diff`.
        order: the order of the derivatives.

    Return:
        the spatial gradients of the input feature map.

    Shape:
        - Input: :math:`(B, C, D, H, W)`. D, H, W are spatial dimensions, gradient is calculated w.r.t to them.
        - Output: :math:`(B, C, 3, D, H, W)` or :math:`(B, C, 6, D, H, W)`

    Examples:
        >>> input = torch.rand(1, 4, 2, 4, 4)
        >>> output = spatial_gradient3d(input)
        >>> output.shape
        torch.Size([1, 4, 3, 2, 4, 4])
    """
    if not isinstance(input, torch.Tensor):
        raise TypeError("Input type is not a torch.Tensor. Got {}".format(type(input)))

    if not len(input.shape) == 5:
        raise ValueError("Invalid input shape, we expect BxCxDxHxW. Got: {}".format(input.shape))
    # allocate kernel
    kernel: torch.Tensor = get_spatial_gradient_kernel3d(mode, order)

    # prepare kernel
    b, c, d, h, w = input.shape
    tmp_kernel: torch.Tensor = kernel.to(input).detach()
    tmp_kernel = tmp_kernel.repeat(c, 1, 1, 1, 1)

    # convolve input tensor with grad kernel
    kernel_flip: torch.Tensor = tmp_kernel.flip(-3)

    # Pad with "replicate for spatial dims, but with zeros for channel
    spatial_pad = [
        kernel.size(2) // 2,
        kernel.size(2) // 2,
        kernel.size(3) // 2,
        kernel.size(3) // 2,
        kernel.size(4) // 2,
        kernel.size(4) // 2,
    ]
    out_ch: int = 6 if order == 2 else 3
    return F.conv3d(F.pad(input, spatial_pad, 'replicate'), kernel_flip, padding=0, groups=c).view(
        b, c, out_ch, d, h, w
    )

def sobel(input: torch.Tensor, normalized: bool = True, eps: float = 1e-6) -> torch.Tensor:
    r"""Computes the Sobel operator and returns the magnitude per channel.

    .. image:: _static/img/sobel.png

    Args:
        input: the input image with shape :math:`(B,C,H,W)`.
        normalized: if True, L1 norm of the kernel is set to 1.
        eps: regularization number to avoid NaN during backprop.

    Return:
        the sobel edge gradient magnitudes map with shape :math:`(B,C,H,W)`.

    Example:
        >>> input = torch.rand(1, 3, 4, 4)
        >>> output = sobel(input)  # 1x3x4x4
        >>> output.shape
        torch.Size([1, 3, 4, 4])
    """
    if not isinstance(input, torch.Tensor):
        raise TypeError("Input type is not a torch.Tensor. Got {}".format(type(input)))

    if not len(input.shape) == 4:
        raise ValueError("Invalid input shape, we expect BxCxHxW. Got: {}".format(input.shape))

    # comput the x/y gradients
    edges: torch.Tensor = spatial_gradient(input, normalized=normalized)

    # unpack the edges
    gx: torch.Tensor = edges[:, :, 0]
    gy: torch.Tensor = edges[:, :, 1]

    # compute gradient maginitude
    magnitude: torch.Tensor = torch.sqrt(gx * gx + gy * gy + eps)

    return magnitude

class SpatialGradient(nn.Module):
    r"""Computes the first order image derivative in both x and y using a Sobel
    operator.

    Args:
        mode: derivatives modality, can be: `sobel` or `diff`.
        order: the order of the derivatives.
        normalized: whether the output is normalized.

    Return:
        the sobel edges of the input feature map.

    Shape:
        - Input: :math:`(B, C, H, W)`
        - Output: :math:`(B, C, 2, H, W)`

    Examples:
        >>> input = torch.rand(1, 3, 4, 4)
        >>> output = SpatialGradient()(input)  # 1x3x2x4x4
    """

    def __init__(self, mode: str = 'sobel', order: int = 1, normalized: bool = True) -> None:
        super(SpatialGradient, self).__init__()
        self.normalized: bool = normalized
        self.order: int = order
        self.mode: str = mode

    def __repr__(self) -> str:
        return (
            self.__class__.__name__ + '('
            'order=' + str(self.order) + ', ' + 'normalized=' + str(self.normalized) + ', ' + 'mode=' + self.mode + ')'
        )

    def forward(self, input: torch.Tensor) -> torch.Tensor:
        return spatial_gradient(input, self.mode, self.order, self.normalized)

class SpatialGradient3d(nn.Module):
    r"""Computes the first and second order volume derivative in x, y and d using a diff
    operator.

    Args:
        mode: derivatives modality, can be: `sobel` or `diff`.
        order: the order of the derivatives.

    Return:
        the spatial gradients of the input feature map.

    Shape:
        - Input: :math:`(B, C, D, H, W)`. D, H, W are spatial dimensions, gradient is calculated w.r.t to them.
        - Output: :math:`(B, C, 3, D, H, W)` or :math:`(B, C, 6, D, H, W)`

    Examples:
        >>> input = torch.rand(1, 4, 2, 4, 4)
        >>> output = SpatialGradient3d()(input)
        >>> output.shape
        torch.Size([1, 4, 3, 2, 4, 4])
    """

    def __init__(self, mode: str = 'diff', order: int = 1) -> None:
        super(SpatialGradient3d, self).__init__()
        self.order: int = order
        self.mode: str = mode
        self.kernel = get_spatial_gradient_kernel3d(mode, order)
        return

    def __repr__(self) -> str:
        return self.__class__.__name__ + '(' 'order=' + str(self.order) + ', ' + 'mode=' + self.mode + ')'

    def forward(self, input: torch.Tensor) -> torch.Tensor:  # type: ignore
        return spatial_gradient3d(input, self.mode, self.order)

class Sobel(nn.Module):
    r"""Computes the Sobel operator and returns the magnitude per channel.

    Args:
        normalized: if True, L1 norm of the kernel is set to 1.
        eps: regularization number to avoid NaN during backprop.

    Return:
        the sobel edge gradient magnitudes map.

    Shape:
        - Input: :math:`(B, C, H, W)`
        - Output: :math:`(B, C, H, W)`

    Examples:
        >>> input = torch.rand(1, 3, 4, 4)
        >>> output = Sobel()(input)  # 1x3x4x4
    """

    def __init__(self, normalized: bool = True, eps: float = 1e-6) -> None:
        super(Sobel, self).__init__()
        self.normalized: bool = normalized
        self.eps: float = eps

    def __repr__(self) -> str:
        return self.__class__.__name__ + '(' 'normalized=' + str(self.normalized) + ')'

    def forward(self, input: torch.Tensor) -> torch.Tensor:
        return sobel(input, self.normalized, self.eps)


import http.client, urllib.request, urllib.parse, urllib.error, base64, json
from pprint import pprint

class GetImage:

    def __init__(self, key):
        self.key = key

    def getImage(self, keywords):

        search_string = ""

        for x in keywords:
            search_string = search_string + " " + x

        headers = {
            # Request headers
            'Ocp-Apim-Subscription-Key': self.key,
        }

        params = urllib.parse.urlencode({
            # Request parameters
            'q': search_string,
            'count': '1',
            'offset': '0',
            'mkt': 'en-us',
            'safeSearch': 'Strict',
        })

        try:
            conn = http.client.HTTPSConnection('api.cognitive.microsoft.com')
            conn.request("GET", "/bing/v5.0/images/search?%s" % params, "{body}", headers)
            response = conn.getresponse()
            data = json.loads(response.read().decode('utf-8'))
            conn.close()

            try:
                return data['value'][0]['contentUrl']
            except IndexError as e:
                print("David wants to output this error: {}".format(e))
                return None
        except Exception as e:
            print("[Errno {0}] {1}".format(e.errno, e.strerror))


# Запросите у пользователя значения выручки и издержек фирмы.
# Определите, с каким финансовым результатом работает фирма (прибыль — выручка больше издержек, или убыток — издержки больше выручки).
# Выведите соответствующее сообщение. Если фирма отработала с прибылью, вычислите рентабельность выручки (соотношение прибыли к выручке).
# Далее запросите численность сотрудников фирмы и определите прибыль фирмы в расчете на одного сотрудника.

print('Начало программы. Практическое задание 5. Урок 1.')

user_incom = int(input('Введите выручку (доход) компании: \n'))
user_cost = int(input('Введите издержки (рассходы) компании: \n'))
profit = None
loss = None
worker_count = None

if user_incom > user_cost:
    profit = user_incom - user_cost
    print(f'Выручка компании составляет {profit}. Соотношение прибыли к выручке = {profit / user_incom * 100}%')
    worker_count = int(input('Введите количество сотрудников компании: \n'))
    print(f'Прибыль фирмы в расчете на одного сотрудника: {profit / worker_count}')
else:
    loss = user_cost - user_incom
    print(f'Убыток компании составялет {loss}')


import os
from barcode_test_executer import BarcodeTestExecuter

class Test(BarcodeTestExecuter):
    # Input:
    # bin_folder: folder contain barcode executable
    def run(self, bin_folder):
        spec_file_path = os.path.dirname(os.path.abspath(__file__))
        params = '-simple -single -all -csv'
        test_path = os.path.dirname(spec_file_path)
        test_data = []
        test_data_path = os.path.join(test_path, "test_data")
        for name in os.listdir(test_data_path):
            if name.endswith((".tif", ".tiff", ".png", ".jpg", ".bmp")):
                image_path = os.path.join(test_data_path, name)
                test_data.append(image_path)

        return self.execute_test(bin_folder, params, test_data)


import random

MAX_GUESS = 100

randomNumber = random.randint(1, MAX_GUESS )

print("Welcome to the Number Guessing Game, hosted by the Python Host App Sample.")
print("Try to guess the secret number between 1 and", MAX_GUESS)

playerGuess = -1
numGuesses = 0

while randomNumber != playerGuess:
    playerGuess = int(input("Enter an integer from 1 to " + str(MAX_GUESS) + ": "))
    numGuesses += 1

    if playerGuess < randomNumber:
        print("You guessed too low; try again!")
    elif playerGuess > randomNumber:
        print("You guessed too high; try again!")

print("Congratulations! You guessed the number in", numGuesses, "tries.")
input("Press any key to exit...")


import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread("avatar.jpg",cv2.IMREAD_GRAYSCALE)

ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
thresh6 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 3)
titles = ['BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV', 'ADAPTIVE']
images = [thresh1, thresh2, thresh3, thresh4, thresh5, thresh6]

for i in range(6):
    plt.subplot(3,2,i+1),
    plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([1]), plt.yticks([1])
plt.show()


"""
Helioviewer Client tests
"""
from __future__ import absolute_import

import os

import sunpy
import sunpy.map
import pytest
from sunpy.net.helioviewer import HelioviewerClient
from sunpy.extern.six.moves import urllib

from sunpy.tests.helpers import skip_glymur

@pytest.fixture(scope="function")
def client():
    """
    Fixture to create a client and skip tests if not available
    """
    try:
        client = HelioviewerClient()
        client.sources = client.get_data_sources()
        return client
    except urllib.error.HTTPError as e:
        print("There's a HTTP problem {} {}".format(e.code, e.args))
        pytest.skip("HTTP error {}".format(e.code))

@pytest.mark.remote_data
class TestHelioviewerClient:
    """Tests the Helioviewer.org API Client class"""

    def test_get_datasources(self, client):
        """Makes sure datasource query returns a valid result and source id
        is casted to an integer"""
        assert type(client.sources['SDO']['AIA']['AIA']['171']['sourceId']) is int

    def test_get_closest_image(self, client):
        """Tests getClosestImage API method"""
        # check basic query
        im1 = client.get_closest_image('1994/01/01',
                                       observatory='SOHO',
                                       instrument='EIT',
                                       detector='EIT',
                                       measurement='195')
        assert im1['width'] == im1['height'] == 1024

        # result should be same when using source id to query
        source_id = client.sources['SOHO']['EIT']['EIT']['195']['sourceId']

        im2 = client.get_closest_image('1994/01/01', sourceId=source_id)

        assert im1 == im2

    @skip_glymur
    def test_download_jp2(self, client):
        """Tests getJP2Image API method"""
        filepath = client.download_jp2('2020/01/01', observatory='SOHO',
                                       instrument='MDI', detector='MDI',
                                       measurement='continuum')
        map_ = sunpy.map.Map(filepath)
        assert isinstance(map_, sunpy.map.GenericMap)

    @skip_glymur
    def test_download_jp2_directory_not_exist(self, client, tmpdir):
        """Tests getJP2Image API method"""

        filepath = client.download_jp2(
            '2020/01/01',
            observatory='SOHO',
            instrument='MDI',
            detector='MDI',
            measurement='continuum',
            directory=os.path.join(str(tmpdir), 'directorynotexist'))

        assert 'directorynotexist' in filepath