# -*- coding: utf-8 -*-

# Copyright 2012-2015 Calculate Ltd. http://www.calculate-linux.org
#
#  Session management
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import os
import datetime
import threading
import random
import pickle
from calculate.core.server.core_interfaces import CoreServiceInterface
from cert_cmd import find_cert_id


class CoreWsdl(CoreServiceInterface):
    sid_locker = threading.Lock()

    # delete client session from file (close session)
    def del_sid_from_file(self, sid):
        try:
            # temp file
            sid_file = self.sids_file
            sid_file_t = sid_file + 'temp'

            with self.sid_locker:
                fd = open(sid_file, 'r')
                ft = open(sid_file_t, 'w')
                while True:
                    try:
                        # read all on one record
                        list_sid = pickle.load(fd)
                    except (EOFError, IOError, KeyError):
                        break
                    # Leave all but removed
                    if sid != list_sid[0]:
                        pickle.dump(list_sid, ft)
                fd.close()
                ft.close()

                # copy all from temp file
                ft = open(sid_file_t, 'rb')
                fd = open(sid_file, 'wb')
                ft.seek(0)
                fd.write(ft.read())
                ft.close()
                fd.close()
                # delete temp file
                os.unlink(sid_file_t)
                return ['0']
        except (IOError, EOFError, KeyError, OSError):
            return ['1']

    # find session id in file
    def find_sid_in_file(self, sid):
        sid_file = self.sids_file
        # create, if file not exists
        with self.sid_locker:
            if not os.path.exists(sid_file):
                temp = open(sid_file, 'w')
                temp.close()
            fd = open(sid_file, 'r')
            while True:
                try:
                    # read all on one record
                    list_sid = pickle.load(fd)
                except (EOFError, IOError, KeyError):
                    break
                # if session id found
                if sid == list_sid[0]:
                    fd.close()
                    return 1
            fd.close()
        return 0

    # add session id in file
    def add_sid_in_file(self, sid, cert_id, lang):
        # list Format (session number, cert number, time start session)
        list_sid = [sid, cert_id, datetime.datetime.now()]
        # session's file
        if not os.path.exists(self.sids):
            os.mkdir(self.sids)
        sids_dir = self.sids
        sid_file = sids_dir + "/%d.sid" % sid

        # create session's file
        with self.sid_locker:
            fp = open(sid_file, 'w')
            sid_list = [sid, 0, 0, lang]
            pickle.dump(sid_list, fp)
            fp.close()

            # add session in list sessions
            fd = open(self.sids_file, 'a')
            pickle.dump(list_sid, fd)
            fd.close()
        return 0

    def set_sid_lang(self, sid, lang):
        sids_dir = self.sids
        sid_file = os.path.join(sids_dir, "%d.sid" % sid)
        with self.sid_locker:
            if not os.path.isfile(sid_file):
                fp = open(sid_file, 'w')
                fp.close()
            fd = open(sid_file, 'r')
            try:
                list_sid = pickle.load(fd)
            except (EOFError, KeyError, IOError):
                list_sid = [sid, 0, 0, lang]
            fd.close()

            fp = open(sid_file, 'w')
            list_sid[3] = lang
            pickle.dump(list_sid, fp)
            fp.close()

    # issue number of new session (and registered its)
    def sid_cmp(self, sid, cert_id, lang):
        if sid < 0 or sid > self.max_sid:
            sid = 0
        session = 1
        # if session is new
        if sid == 0:
            while True:
                new_sid = random.randint(1, self.max_sid)
                # flag = 1 - exists, 0 - missing in SID_FILE
                if self.find_sid_in_file(new_sid) == 0:
                    self.add_sid_in_file(new_sid, cert_id, lang)
                    sid = new_sid
                    break
        # if session is old
        else:
            # find number in file registered
            # if not registered
            if not self.find_sid_in_file(sid):
                # add session id in file
                self.add_sid_in_file(sid, cert_id, lang)
            else:
                self.set_sid_lang(sid, lang)
                # set - old session
                session = 0

        # session id and flag (new or old) session
        return [sid, session]

    def serv_init_session(self, sid, lang):
        day_cert = 600
        cur_thread = threading.currentThread()
        certificate = cur_thread.client_cert
        if certificate is None:
            return [-3], [0]

        checked_id = find_cert_id(certificate, self.data_path, self.certbase)
        try:
            if int(checked_id) < 1:
                return [-4], [0]
        except ValueError:
            return [-4], [0]
        results = []
        cert_id = checked_id
        with open(self.certbase) as fd:
            t = fd.read()
            # See each line
            for line in t.splitlines():
                # and each word in line
                words = line.split()
                # if in line present certificate id
                if len(words) > 3:
                    if words[0] == checked_id:
                        results.append(checked_id)
                        date = datetime.datetime.strptime(
                            words[2] + ' ' + words[3], '%Y-%m-%d %H:%M:%S.%f')
                        d = datetime.datetime.now() - date
                        v = day_cert - d.days  # How many days left certificate
                        if v < 0:
                            # Method deleted certificate
                            v = -2  # expiry date has passed
                        elif v > 60:  # For a long time, is not displayed to
                            # the client
                            v = -1
                        results.append(v)
                        # return results
        if not results:
            return [-4], [0]

        return results, self.sid_cmp(sid, cert_id, lang)

    def serv_sid_info(self, sid):
        """ Get information about sid """
        cert_id = 0
        results = []
        sid_file = self.sids_file
        with self.sid_locker:
            fd = open(sid_file, 'r')
            while 1:
                try:
                    # read all on one record
                    list_sid = pickle.load(fd)
                except (IOError, KeyError, EOFError):
                    break
                # if sid found
                if sid == list_sid[0]:
                    cert_id = list_sid[1]
            fd.close()

        # Get information about sid
        if cert_id == 0:
            return ["-1"]

        with self.sid_locker:
            with open(self.certbase) as fd:
                t = fd.read()
                # See each line
                for line in t.splitlines():
                    # and each word in line
                    words = line.split()
                    # if in line present certificate id
                    if words[0] == str(cert_id):
                        # certificate id
                        results.append(words[0])
                        # Date issue certificate
                        results.append(words[2] + ' ' + words[3])
                        # ip
                        results.append(words[4])
                        # mac
                        results.append(words[5])
                        # client type
                        results.append(words[6])
                        if not os.path.exists(self.sids):
                            os.makedirs(self.sids)
                        sid_path = self.sids + "/%d.sid" % sid
                        with open(sid_path) as fs:
                            # read info about session
                            sid_inf = pickle.load(fs)
                        # flag absence client
                        results.append(str(sid_inf[2]))

                        return results
        return ["-2"]
