# -*- coding: utf-8 -*-
import os
from collections import namedtuple

from ppms.migration.packet import *


ValuerangeChanges = namedtuple('ValuerangeChanges', ['before_hash',
                                                     'after_hash',
                                                     'sourcecode'])

DIS_TO_CHANGE = {'001230': ValuerangeChanges('d41d8cd98f00b204e9800998ecf8427e',
                                             '122f4bb03e744e3a42112a2c6b8b4610',
                                             '''from ppms import ppms
from ppms.module_subclasses.resource import start_end_period_processInput, start_end_period_checkInput

def checkInput(di, oldvalue):
    return start_end_period_checkInput(di, oldvalue)

def processInput(di, oldvalue):
    return start_end_period_processInput(di, oldvalue)

checkInput.deps = ('DI001229', 'DI001231')
processInput.deps = ('', )'''),
                 '001231': ValuerangeChanges('d41d8cd98f00b204e9800998ecf8427e',
                                             '78a8c423e9e58d3ba0137a1dfbc3bd20',
                                             '''from ppms import ppms
from ppms.module_subclasses.resource import start_end_period_processInput, start_end_period_checkInput

def checkInput(di, oldvalue):
    return start_end_period_checkInput(di, oldvalue)

def processInput(di, oldvalue):
    return start_end_period_processInput(di, oldvalue)

checkInput.dpes = ('DI001229', 'DI001230')
processInput.deps = ('', )'''),
                 '002653': ValuerangeChanges('d41d8cd98f00b204e9800998ecf8427e',
                                             '14b213635fe046ddc87efb6e0ac8c7ce',
                                             '''from ppms.module_subclasses.resource import summarize_periods_process_input

def processInput(di, oldvalue):
    return summarize_periods_process_input(di, oldvalue)

processInput.deps = ('DI001218', )'''),
                 '009753': ValuerangeChanges('c5671cd7cf8fcf9f73ea1e4118e5c315',
                                             'ad4044caafe9534aa8622127f01629f5',
                                             '''from ppms.module_subclasses.resource import parent_res_id_process_input

def processInput(di, oldvalue):
    return parent_res_id_process_input(di, oldvalue)

processInput.deps = ('', )'''),
                 '001240': ValuerangeChanges('d41d8cd98f00b204e9800998ecf8427e',
                                             '9fb781e5e6852a527fc43887e5779714',
                                             '''from ppms.module_subclasses.resource import avail_cap_base_computeOutput

def computeOutput(di):
    return avail_cap_base_computeOutput(di)

computeOutput.deps = ('DI001234', 'DI001233',
                      # Factor 1
                      'DI001249', 'DI001250', 'DI001247', 'DI001248',
                      # Factor 2
                      'DI001255', 'DI001256', 'DI001253', 'DI001254',
                      # Factor 3
                      'DI001261', 'DI001262', 'DI001259', 'DI001260',
                      # Factor 4
                      'DI001267', 'DI001268', 'DI001265', 'DI001266',
                      # Factor 5
                      'DI001273', 'DI001274', 'DI001271', 'DI001272',
                      )''')}


class ChangeDataitems(ChangeDTPPacket):
    '''Port the necessary dataitem changes for the new period aggregation'''
    version = 1
    done_after_success = True
    run_on_startup = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 9958

    def fix(self, runner):
        failures = 0

        # Make 'em PY valueranges
        for di in ('001230', '001231', '002653', '001240'):
            record = self.get_record(412, [di], [1990])
            if not record:
                failures += 1
                break

            if not self.change_value(record, 'wb_type', '', 'PY'):
                failures += 1

        # Remove the exits
        for di, exit in (('001230', '00000004'), ('002653', '00000120')):
            record = self.get_record(412, [di], [252])
            if not record:
                failures += 1
                break

            if not self.change_value(record, 'exit_id', exit, '-'):
                failures += 1

        if failures > 0:
            return self.fail()

        return self.success()


class ChangeValueranges(MigratePythonPacket):
    '''Port the necessary value range changes for the new period aggregation'''
    version = 1
    done_after_success = True
    run_on_startup = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 9958

    def fix(self, runner):
        failures = 0
        for di_num, (before_hash, after_hash, code) in DIS_TO_CHANGE.items():
            fix_func = lambda _: code

            if not self.migrate_python(before_hash, after_hash,
                                       self.CU_TYPE_DATAITEM, di_num, fix_func):
                failures += 1

        if failures > 0:
            return self.fail()

        return self.success()


class ChangeModuleMacros(MigratePythonPacket):
    '''Port the necessary module macro changes for the new period aggregation'''
    version = 1
    done_after_success = True
    run_on_startup = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 9958

    DATA = {'0099DT': ()}

    def fix(self, runner):
        fix_func = lambda old_code: ''
        if not self.migrate_python('698b9a025a75ed376735137b7d44950b',
                                   'd41d8cd98f00b204e9800998ecf8427e',
                                   self.CU_TYPE_MODULE, '0099DT', fix_func):
            return self.fail()

        return self.success()


class ChangeModuleSubclasses(ChangeDTPPacket):
    '''Port the necessary module subclasses for the new period aggregation'''
    version = 1
    done_after_success = True
    run_on_startup = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 9958

    MODULE_SUBCLASSES = {'0099DQ': 'ppms.module_subclasses.resource.ResourceBase',
                         '0099DT': 'ppms.module_subclasses.resource.ResourceDatasheet'}

    def fix(self, runner):
        failures = 0

        for module_id, subclass in self.MODULE_SUBCLASSES.items():
            record = self.get_record(405, [module_id], [56952])
            if not self.change_value(record, 'python_module_subclass', '', subclass) and \
                    not self.change_value(record, 'python_module_subclass', 'ppms.module_subclasses.base_class.Base',
                                          subclass):
                failures += 1

        if failures > 0:
            return self.fail()

        return self.success()


class PortSQLStatements(SQLPacket):
    '''Port the necessary sql statements for the new period aggregation'''
    version = 1
    done_after_success = True
    run_on_startup = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 9958

    fname = 'wi9958_period_creation_and_aggregation.sql'

    query = '000682'

    def query_exists(self, query):
        """Check if a query (DT342) already exists."""
        query_exists_in_db = self.select_or_log(
            "select count(*) from DT342 where DI024359 = '{query}'".format(query=query))
        return bool(query_exists_in_db[0][0])

    def fix(self, runner):
        # the query might already be created by a server packet so check if it already exists
        if self.query_exists(self.query):
            self.log('Packet is not needed as the query already exists')
            return self.success()
        sqlpath = self.get_sql_file_path(self.sql_planta_de_dbms, self.fname)
        queries = self.get_queries_from_file(sqlpath)

        for query in queries:
            self.modify_and_log(query)

        return self.success()


class PortSchema(SQLPacket):
    '''Port the necessary db schema changes for the new period aggregation'''
    version = 1
    done_after_success = True
    run_on_startup = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 9958

    def fix(self, runner):
        self.port_tables(runner)
        self.port_function(runner)
        self.port_procedure(runner)

        return self.success()

    def port_tables(self, runner):
        self.log_heading('Porting the tables')
        fname = 'wi9958_period_creation_and_aggregation_tables.sql'
        sqlpath = self.get_sql_file_path(self.sql_planta_de_dbms, fname)

        queries = self.get_queries_from_file(sqlpath)

        for query in queries:
            self.modify_and_log(query)

    def port_procedure(self, runner):
        self.log_heading('Porting the procedure')
        fname = 'wi9958_period_creation_and_aggregation_procedure.sql'
        sqlpath = self.get_sql_file_path(self.sql_planta_de_dbms, fname)

        with open(sqlpath) as f:
            query = f.read()

        self.modify_and_log(query)

    def port_function(self, runner):
        self.log_heading('Porting the function')
        fname = 'wi9958_period_creation_and_aggregation_function.sql'
        sqlpath = self.get_sql_file_path(self.sql_planta_de_dbms, fname)

        with open(sqlpath) as f:
            query = f.read()

        self.modify_and_log(query)
