#!/usr/bin/python3
# -*- coding: utf-8 -*-

import multiprocessing
from optparse import OptionParser
import os
import re
import platform
import sys
PYSIDEVER = 6
try:
    from PySide6 import QtCore, QtGui, QtWidgets
    from PySide6.QtWidgets import QApplication, QFileDialog, QListWidgetItem, QMessageBox
    from PySide6.QtCore import QFile
    from ui6_DlgSetUtsusemiEnv import Ui_MainWindow
except:
    from PySide2 import QtCore, QtGui, QtWidgets
    # from PySide2.QtUiTools import QUiLoader
    from PySide2.QtWidgets import QApplication, QFileDialog, QListWidgetItem, QMessageBox
    from PySide2.QtCore import QFile
    from ui2_DlgSetUtsusemiEnv import Ui_MainWindow
    PYSIDEVER = 2

if sys.platform == 'win32':
    HOME = os.environ.get("USERPROFILE")
elif sys.platform == 'darwin':
    HOME = os.environ.get("HOME")
elif sys.platform == 'linux2':
    HOME = os.environ.get("HOME")
else:
    HOME = os.curdir

# UTSUSEMI_DATA_DIRとUTSUSEMI_USR_DIRのベースディレクトリの初期値
BASE_DIR = os.path.join(HOME, "Documents", "Utsusemi")

# "utsusemienv.cfg"のパス
FILE_CONFIG = os.environ.get("CONFFILE_ENV")
FILE_CONFIG_DIR = os.path.dirname(FILE_CONFIG)

# カレントディレクトリ
CURRENT_DIR = os.getcwd()

# 設定対象の環境変数
UTSUSEMI_INST_CODE = "UTSUSEMI_INST_CODE"
UTSUSEMI_LOG_QUIET = "UTSUSEMI_LOG_QUIET"
UTSUSEMI_DEBUGMODE = "UTSUSEMI_DEBUGMODE"
UTSUSEMI_MULTH = "UTSUSEMI_MULTH"
UTSUSEMI_DATA_DIR = "UTSUSEMI_DATA_DIR"
UTSUSEMI_USR_DIR = "UTSUSEMI_USR_DIR"
UTSUSEMI_WORK_DIR = "UTSUSEMI_WORK_DIR"
UTSUSEMI_DEFAULT_FONTSIZE = "UTSUSEMI_DEFAULT_FONTSIZE"

# 環境変数のリスト
VARS = [
    UTSUSEMI_INST_CODE,
    UTSUSEMI_LOG_QUIET,
    UTSUSEMI_DEBUGMODE,
    UTSUSEMI_MULTH,
    UTSUSEMI_DATA_DIR,
    UTSUSEMI_USR_DIR,
    UTSUSEMI_WORK_DIR,
    UTSUSEMI_DEFAULT_FONTSIZE
]

# ビームライン選択用の辞書
BEAMLINES = {
    "SIK": {'line': 1, 'name': "4SEASONS"},
    "DNA": {'line': 2, 'name': "DNA"},
    "NBR": {'line': 10, 'name': "Noboru"},
    "HPN": {'line': 11, 'name': "PLANET"},
    "AMR": {'line': 14, 'name': "AMATERAS"},
    "SAS": {'line': 15, 'name': "TAIKAN"},
    "ENG": {'line': 19, 'name': "TAKUMI"},
}

"""
if sys.platform == 'darwin' or sys.platform == 'linux':
    # MacとLinuxではDNAも使用可能(Noboru is only command line)
    BEAMLINES["DNA"] = {'line': 2, 'name': "DNA"}
    # BEAMLINES["NBR"] = {'line': 10, 'name': "Noboru"}
"""

# Y/N←→真偽値 変換用の辞書
LOG_QUIET = {"Y": True, "N": False}


class Param:
    def __init__(self):
        self.data_dir = os.path.join(BASE_DIR, "DATA")
        self.usr_dir = os.path.join(BASE_DIR, "HOME")
        self.work_dir = self.usr_dir
        self.multh = 2 if multiprocessing.cpu_count() >= 2 else 1
        self.log_quiet = True
        self.debug_mode = False
        self.inst_code = "SIK"
        self.def_fontsize = 12
        self.loaded = {x: False for x in VARS}

    def load(self, path):
        if not os.path.isfile(path):
            return
        try:
            with open(path) as f:
                d = {}
                for x in f.readlines():
                    if "=" in x:
                        key, val = x.strip().split("=", 1)
                        d[key] = re.sub(r'[\"\'\n\r]+', '', val)
                for key, val in d.items():
                    msg = ""
                    if key == UTSUSEMI_MULTH:
                        try:
                            self.multh = int(val)
                        except:
                            msg = "MULTH: not an integer: >>>" + val + "<<<"
                    elif key == UTSUSEMI_INST_CODE:
                        self.inst_code = val
                    elif key == UTSUSEMI_LOG_QUIET:
                        if val in ("Y", "N"):
                            self.log_quiet = ("Y" == val)
                        else:
                            msg = "LOG_QUIET: illegal value: >>>" + val + "<<<"
                    elif key == UTSUSEMI_DEBUGMODE:
                        if val in ("Y", "N"):
                            self.debug_mode = ("Y" == val)
                        else:
                            msg = "DEBUGMODE: illegal value: >>>" + val + "<<<"
                    elif key == UTSUSEMI_USR_DIR:
                        self.usr_dir = val
                    elif key == UTSUSEMI_DATA_DIR:
                        self.data_dir = val.strip('"')
                    elif key == UTSUSEMI_WORK_DIR:
                        self.work_dir = val.strip('"')
                    elif key == UTSUSEMI_DEFAULT_FONTSIZE:
                        self.def_fontsize = int(val)

                    if key in self.loaded.keys() and not msg:
                        self.loaded[key] = True
                    if msg:
                        QMessageBox.warning(None, "PARAMETER ERROR", msg)
        except Exception as e:
            QMessageBox.warning(None, "LOAD ERROR",
                                "unknown load error: " + str(e))

    def bad_paths(self):
        d = self.data_dir
        u = self.usr_dir
        w = self.work_dir
        ret = []
        if not os.path.exists(d) or not os.path.isdir(d):
            ret.append(d)
        if not os.path.exists(u) or not os.path.isdir(u):
            ret.append(u)
        if not os.path.exists(w) or not os.path.isdir(w):
            ret.append(w)
        return ret

    def dump(self, path):
        bad = self.bad_paths()
        if bad:
            return bad
        with open(path, "w") as f:
            f.write("%s=%s\n" % (UTSUSEMI_INST_CODE, self.inst_code))
            f.write("%s=%s\n" % (UTSUSEMI_LOG_QUIET, ("Y" if self.log_quiet else "N")))
            f.write("%s=%s\n" % (UTSUSEMI_DEBUGMODE, ("Y" if self.debug_mode else "N")))
            f.write("%s=%d\n" % (UTSUSEMI_MULTH, self.multh))
            f.write("%s=\"%s\"\n" % (UTSUSEMI_DATA_DIR, self.data_dir))
            f.write("%s=\"%s\"\n" % (UTSUSEMI_USR_DIR, self.usr_dir))
            f.write("%s=\"%s\"\n" % (UTSUSEMI_WORK_DIR, self.work_dir))
            f.write("%s=%d\n" % (UTSUSEMI_DEFAULT_FONTSIZE, self.def_fontsize))
        return []


class Main(QtWidgets.QMainWindow):
    def __init__(self, parent):
        # file = QFile(path)
        # file.open(QFile.ReadOnly)
        # loader = QUiLoader()
        # self = loader.load(file)
        super(Main, self).__init__(parent)
        self.ui = Ui_MainWindow()
        if self.ui is None:
            return
        self.ui.setupUi(self)
        self.param = Param()
        self.getGui()
        self.setup()
        self.connections()
        self.show()

    def getGui(self):
        self.beamList = self.findChild(QtWidgets.QListWidget, 'beamList')
        self.cbLogQuiet = self.findChild(QtWidgets.QCheckBox, 'cbLogQuiet')
        self.spnFontSize = self.findChild(QtWidgets.QSpinBox, 'spnFontSize')
        self.spnNumThread = self.findChild(QtWidgets.QSpinBox, 'spnNumThread')
        self.cbDebugMode = self.findChild(QtWidgets.QCheckBox, 'cbDebugMode')
        self.buttonBox = self.findChild(QtWidgets.QDialogButtonBox, 'buttonBox')
        self.txtDataDir = self.findChild(QtWidgets.QLineEdit, 'txtDataDir')
        self.btDataDir = self.findChild(QtWidgets.QPushButton, 'btDataDir')
        self.txtUsrDir = self.findChild(QtWidgets.QLineEdit, 'txtUsrDir')
        self.btUsrDir = self.findChild(QtWidgets.QPushButton, 'btUsrDir')
        self.txtWorkDir = self.findChild(QtWidgets.QLineEdit, 'txtWorkDir')
        self.btWorkDir = self.findChild(QtWidgets.QPushButton, 'btWorkDir')
        
    def setup(self):
        self.items = {}
        for x, vs in BEAMLINES.items():
            s = "BL" + str(vs['line']).zfill(2) + ":" + \
                x + "(" + vs['name'] + ")"
            item = QListWidgetItem(s)
            self.beamList.addItem(item)
            self.items[x] = item
        # self.beamList.setCurrentItem(self.items["SIK"])

        self.spnNumThread.setRange(1, multiprocessing.cpu_count())
        if FILE_CONFIG is None:
            msg = """You need to define an environment variable 'CONFFILE_ENV'
whose value is the filepath of utsusemienv.cfg"""
            QMessageBox.critical(self, "Missing CONFFILE_ENV", msg)
            sys.exit(1)
        self.param.load(FILE_CONFIG)
        self.txtDataDir.setText(self.param.data_dir)
        self.txtUsrDir.setText(self.param.usr_dir)
        self.txtWorkDir.setText(self.param.work_dir)
        self.spnNumThread.setValue(self.param.multh)
        self.spnFontSize.setValue(self.param.def_fontsize)
        if self.param.log_quiet:
            print("QUIET")
            self.cbLogQuiet.setChecked(True)
        if self.param.debug_mode:
            print("DEBUG_MODE")
            self.cbDebugMode.setChecked(True)
        self.beamList.setCurrentItem(self.items[self.param.inst_code])
        # self.beamList.setItemSelected(self.items[self.param.inst_code],True)
        self.items[self.param.inst_code].setSelected(True)

    def connections(self):
        self.buttonBox.accepted.connect(self.save)
        self.buttonBox.rejected.connect(self.quit)
        self.btDataDir.clicked.connect(self.fdData)
        self.btUsrDir.clicked.connect(self.fdUsr)
        self.btWorkDir.clicked.connect(self.fdWork)

    def quit(self, force=True):
        if force:
            app.exit()
            self.close()

    def fdData(self):
        ret = QFileDialog.getExistingDirectory(
            self, "DD", self.param.data_dir)
        if len(ret) > 0:
            UTSUSEMI_DATA_DIR = os.path.normpath(ret)
            self.txtDataDir.setText(UTSUSEMI_DATA_DIR)

    def fdUsr(self):
        ret = QFileDialog.getExistingDirectory(
            self, "DD", self.param.usr_dir)
        if len(ret) > 0:
            UTSUSEMI_USR_DIR = os.path.normpath(ret)
            self.txtUsrDir.setText(UTSUSEMI_USR_DIR)

    def fdWork(self):
        ret = QFileDialog.getExistingDirectory(
            self, "DD", self.param.work_dir)
        if len(ret) > 0:
            UTSUSEMI_WORK_DIR = os.path.normpath(ret)
            self.txtWorkDir.setText(UTSUSEMI_WORK_DIR)

    def save(self):
        d1 = self.txtDataDir.text()
        d2 = self.txtUsrDir.text()
        d3 = self.txtWorkDir.text()
        for d in [d1, d2, d3]:
            if not os.path.exists(d):
                msg = "Not found given folder ({}) . Do you want to make it ?".format(
                    d)
                ret = QMessageBox().warning(None, u"Warning", msg,
                                            QMessageBox.Ok, QMessageBox.Cancel)
                if ret == QMessageBox.Ok:
                    try:
                        os.makedirs(d)
                    except:
                        QMessageBox.warning(None, "ERROR", "No permitted.")
                        return
                else:
                    self.quit()
        self.param.data_dir = d1
        self.param.usr_dir = d2
        self.param.work_dir = d3
        if not os.path.exists(os.path.join(d2, "ana", "xml")):
            try:
                os.makedirs(os.path.join(d2, "ana", "xml"))
            except:
                QMessageBox.warning(
                    None, "WARNING", "Failed to make ana/xml ", QMessageBox.Ok)
        if not os.path.exists(os.path.join(d2, "ana", "tmp")):
            try:
                os.makedirs(os.path.join(d2, "ana", "tmp"))
            except:
                QMessageBox.warning(
                    None, "WARNING", "Failed to make ana/tmp ", QMessageBox.Ok)
        self.param.log_quiet = self.cbLogQuiet.isChecked()
        self.param.debug_mode = self.cbDebugMode.isChecked()
        self.param.multh = self.spnNumThread.value()
        self.param.def_fontsize = int(self.spnFontSize.value())
        citem = self.beamList.currentItem()
        for k, item in self.items.items():
            if item.text == citem.text:
                self.param.inst_code = k
        if not os.path.exists(FILE_CONFIG_DIR):
            os.makedirs(FILE_CONFIG_DIR)
        bad = self.param.dump(FILE_CONFIG)
        if not bad:
            msg = "new settings were saved"
            QMessageBox.information(self, "Confirmation", msg)
            self.quit()
        msg = "illegal path(s): " + ",".join(bad)
        QMessageBox.warning(self, "ILLEGAL PATHS", msg)


if __name__ == '__main__':
    parser = OptionParser(usage=u'%prog [OPTIONS]')
    parser.add_option(
        '-a', '--alert',
        help='Display alert.',
        action='store_true',
        default=False,
        dest='isAlert'
    )
    parser.add_option(
        '-m', '--message',
        help='Alert message to be shown',
        default=None,
        dest='message')
    (option, args) = parser.parse_args()

    if PYSIDEVER != 6:
        if hasattr(QtCore.Qt, 'AA_EnableHighDpiScaling'):
            QtWidgets.QApplication.setAttribute(
                QtCore.Qt.AA_EnableHighDpiScaling, True)

    app = QApplication(sys.argv)

    if option.isAlert:
        msg = "\n".join([option.message,
                         "",
                         "Run the [Utsusemi Environment Settings] and set up the environment variables."])
        QMessageBox.critical(None, "Missing CONFFILE_ENV", msg)
        sys.exit(1)

    if FILE_CONFIG is None:
        msg = "\n".join(["You need to define an environment variable 'CONFFILE_ENV'"
                         "whose value is the filepath of utsusemienv.cfg"])
        QMessageBox.critical(None, "Missing CONFFILE_ENV", msg)
        sys.exit(1)

    win = Main(None)
    if PYSIDEVER == 6:
        sys.exit(app.exec())
    else:
        sys.exit(app.exec_())
