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

# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
#
#  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.

from __future__ import print_function
import os
import glob
import sys
import time
import datetime
import pickle
from calculate.core.datavars import DataVarsCore
from calculate.core.server.core_interfaces import CoreServiceInterface
from calculate.lib.cl_lang import setLocalTranslate

_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])


def clean(sid_file, pid_file, sid_pid, sids_dir, pids_dir):
    """
    Удалить все файлы сервера после перезапуска
    """
    for fn in (sid_file, pid_file, sid_pid):
        if os.path.exists(fn):
            try:
                os.unlink(fn)
            except OSError:
                pass

    for dn in (sids_dir, pids_dir):
        if os.path.isdir(dn):
            for filename in glob.glob(os.path.join(dn, "*.sid")):
                try:
                    os.unlink(filename)
                except OSError:
                    pass


class CoreWsdl(CoreServiceInterface):
    # watch for process
    @staticmethod
    def watcher_pid_proc(cls, sid, pid):
        period = 2
        time.sleep(period)
        try:
            # while process status "Active"
            while cls.glob_process_dict[pid]['status'] == 1:
                # frequency check
                time.sleep(period)

            cls.delete_pid(cls, sid, pid)
        except IOError as e:
            print('Except IOError', str(e))
        except Exception:
            print(_("PID %d watcher error") % pid)
            try:
                cls.delete_pid(cls, sid, pid)
            except Exception:
                pass
            time.sleep(0.1)

    @staticmethod
    def delete_pid(cls, sid, pid):
        while len(cls.glob_frame_list[pid]) > \
                cls.glob_process_dict[pid]['counter']:
            time.sleep(1)
        methodname = cls.glob_process_dict[pid]['method_name']
        if methodname:
            cls.clear_cache(sid, methodname)
        cls.del_pid(cls, pid)
        cls.del_pid_from_sid_pid(cls, pid)


def monitor(certbase, sid_file):
    """ function to delete old session """
    # Get value of period and lifetime session from DataVars
    try:
        ob = DataVarsCore()
        ob.importCore()

        if not ob.flIniFile():
            sys.exit(1)
        period = float(ob.Get('cl_core_monitor_period'))
        sid_live = float(ob.Get('cl_core_sid_live'))
    except Exception:
        print(_("Variable cl_core_monitor_period or cl_core_sid_live not "
                "found"))
        raise
    # Check lifetime. if necessary, remove
    while True:
        # check session
        try:
            sid_file_t = sid_file + '_temp'
            fd = open(sid_file, 'r')
            ft = open(sid_file_t, 'w')
            while 1:
                try:
                    # read all on one record
                    list_sid = pickle.load(fd)
                except (EOFError, KeyError, IOError):
                    break
                # how time exists session
                delta = datetime.datetime.now() - list_sid[2]
                # if not outdated, then leave
                if delta.seconds < sid_live * 60:
                    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)
        except (IOError, OSError):
            return 1

        # Частота проверки
        time.sleep(60 * period)


# check client's presence
def sid_monitor(sid_fn, sids_dn, cls):
    # check interval
    period = 21
    while True:
        try:
            sids = []
            # create, if file not exists
            if not os.path.exists(sid_fn):
                temp = open(sid_fn, 'w')
                temp.close()
            fd = open(sid_fn, 'r')
            while 1:
                try:
                    # read all on one record
                    list_sid = pickle.load(fd)
                except (EOFError, KeyError, IOError):
                    break
                # add session id in sesession list
                sids.append(list_sid[0])
            fd.close()
        except (IOError, OSError):
            print(_("Error reading SID files"))
            return

        try:
            # for each session
            for filename in sids:
                # find file this session
                sid_path = sids_dn + "/%d.sid" % filename
                with cls.sid_locker:
                    if os.path.isfile(sid_path):
                        with open(sid_path) as fd:
                            # read information about session
                            sid_inf = pickle.load(fd)
                            # if number of missed inspections more 3
                            if sid_inf[1] > 3:
                                # flag client absence
                                sid_inf[2] = 1
                        fd.close()
                        if os.path.isfile(sid_path):
                            # add to digit missed inspections
                            # client constantly nulls this value!
                            ft = open(sid_path, 'w')
                            if sid_inf[1] < 4:
                                sid_inf[1] += 1
                            pickle.dump(sid_inf, ft)
                            ft.close()
        except (IOError, OSError, KeyError):
            pass
        # check period
        time.sleep(period)
