#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
from pathlib import Path

import xmltodict
import lxml.etree as ET


def get_options(schema):

    namespaces = {"xs":"http://www.w3.org/2001/XMLSchema"}

    xsd = ET.parse(schema)
    all_schemas = xsd.findall("xs:simpleType[@name]", namespaces)
    #default_devices = [a.attrib["name"] for a in all_schemas]

    #all_schemas = sorted(all_schemas, key=lambda k: k.attrib['name'])

    all_options = []
    for a in all_schemas:

        try:
            help_title = a.findall("xs:annotation/xs:appinfo", namespaces)[0].text
            help_text = a.findall("xs:annotation/xs:documentation", namespaces)[0].text
        except Exception as e:
            #print("no help")
            help_title = ""
            help_text = ""

        rest = a.findall("xs:restriction/xs:enumeration", namespaces)
        options = [r.attrib["value"] for r in rest]
        all_options.append( {"name": a.attrib["name"].replace("_Type",""),
                             "options": options,
                             "help": help_text
                             })

    return all_options


def rebuild_xml(ob, name):

    root = ET.Element("ObservationBlock")
    root.set("OBID", name)
    for template in ob:
        tpl = ET.SubElement(root,"Template")
        for subsystem in template:
            sub = ET.SubElement(tpl, subsystem)
            if subsystem in ['TPLID', 'TPLName']:
                sub.text = template[subsystem]
            else:
                if subsystem in template and template[subsystem]:
                    for key in template[subsystem]:
                        dev = ET.SubElement(sub, key).text = template[subsystem][key]

    ob_string = (ET.tostring(root, pretty_print=True)).decode()
    return ob_string



class SetupObject(object):
    def __init__(self, path): # it can be ob or ref
        self.path = Path(path)
        self.ext = ".ref" if str(self.path) == "ref" else ".xml"

    @property
    def todos(self):
        todos = []
        filenames = self.path.glob("*"+self.ext)
        for filename in sorted(filenames):
            with open(str(filename)) as xml_file:
                if "ref" in str(self.path):
                    content = xmltodict.parse(xml_file)["ReferenceSetup"]
                    content["filename"] = str(filename)
                else:
                    #print(xml_file)
                    content = xmltodict.parse(xml_file)["ObservationBlock"]#["Template"]
                    content["filename"] = str(filename)
            todos.append(content)
        return todos

    def show(self, id):
        for item in self.todos:
                if "ref" in str(self.path):
                    if item["Script"] == id:
                        return item
                else:
                    if item["Template"]["TPLID"] == id:
                        return item

    def read(self, name):
        for item in self.todos:
                if "ref" in str(self.path):
                    #print(item["filename"])
                    if item["filename"] == str(self.path / (name+self.ext)):
                        return item
                else:
                    if item["filename"] == str(self.path / (name+self.ext)):
                        return item

    def content(self, name):
        return [dict(self.read(name)["Template"])]


class DocObject(object):
    def __init__(self, path): # it is doc
        self.path = Path(path)
        self.ext = ".doc"

    @property
    def todos(self):
        todos = []
        filenames = self.path.glob("*"+self.ext)

        for filename in sorted(filenames):

            with open(str(filename)) as xml_file:
                content = xmltodict.parse(xml_file)["doc"]
                content["filename"] = str(filename)
            todos.append(content)
        return todos

    def read(self, name):

        for item in self.todos:
            if item["filename"] == str(self.path / (name+self.ext)):
                return item["description"]


class ObservationBlockObject(object):
    def __init__(self, path): # it can be ob or ref
        self.path = Path(path)
        self.ext = ".xml"

    @property
    def todos(self):
        todos = []
        filenames = self.path.glob('[!.]*'+self.ext)
        for filename in sorted(filenames):
            #print(filename)
            with open(str(filename)) as xml_file:
                content = xmltodict.parse(xml_file)["ObservationBlock"]
                if not content:
                    content = {}
                content["filename"] = str(filename)
                #content["name"] = content["@OBID"] # just for html compatibility
                if "Template" in content:
                    if type(content["Template"]) != list: # if one template in OB
                        content["Template"] = [content["Template"]]
            todos.append(content)
        return todos

    def show(self, id):
        for item in self.todos:
            if item["@OBID"] == id:
                return item

    def read(self, filename):
        with open(str(filename)) as f:
            # content = json.load(f)
            content = f.read() #json.load(f)
        return content

    def content(self, name):
        if "Template" in self.show(name):
            return self.show(name)["Template"]
        else:
            return []

    def create(self, name):
        if name:
            self.update(name)
        return self.todos

    def update(self, name, data=[]):
        ob_string = rebuild_xml(data, name)
        filename = self.path / (name + self.ext)
        with open(str(filename), "w") as f:
            f.write(ob_string)
            #json.dump(data, f, indent=4)

        return self.todos

    def delete(self, name):
        filename = self.path / (name + self.ext)
        filename.unlink()
        return self.todos


class SchemaObject(object):
    def __init__(self):
        self.schemas =  {
            "InstrumentSetup" : "/opt/tan/share/shins/templates/schema/instrumentSetup.xsd",
            "DetectorSetup"   : "/opt/tan/share/shins/templates/schema/detectorSetup.xsd",
            "TelescopeSetup"  : "/opt/tan/share/shins/templates/schema/telescopeSetup.xsd",
            "TipTiltCtrlSetup": "/opt/tan/share/shins/templates/schema/tiptiltCtrlSetup.xsd",
            "InfoSetup": "/opt/tan/share/shins/templates/schema/infoSetup.xsd",
        }

    def read(self, name):
        path = self.schemas[name]
        return get_options(path)


class SetupObject(object):
    def __init__(self, path): # it can be ob or ref
        self.path = Path(path)
        self.ext = ".ref" if "ref" in str(self.path) else ".xml"

    @property
    def todos(self):
        todos = []
        filenames = self.path.glob("*"+self.ext)
        for filename in sorted(filenames):
            with open(str(filename)) as xml_file:
                try:
                    if "ref" in str(self.path):
                        content = xmltodict.parse(xml_file)["ReferenceSetup"]
                        content["filename"] = str(filename)
                    else:
                        #print(xml_file)
                        content = xmltodict.parse(xml_file)["ObservationBlock"]#["Template"]
                        content["filename"] = str(filename)
                except Exception as e:
                    print(e)
                    raise Exception("invalid xml detected: {}".format(xml_file))
            todos.append(content)
        return todos

    def show(self, id):
        print(id)
        for item in self.todos:
                if "ref" in str(self.path):
                    if item["Script"] == id:
                        return item
                else:
                    if item["Template"]["TPLID"] == id:
                        return item

    def read(self, name):
        for item in self.todos:
                if "ref" in str(self.path):
                    if item["filename"] == str(self.path / (name+self.ext)):
                        print("ref file: "+str(self.path / (name+self.ext)))
                        return item
                else:
                    if item["filename"] == str(self.path / (name+self.ext)):
                        print("def file: "+str(self.path / (name+self.ext)))
                        return item

    def content(self, name):
        return [dict(self.read(name)["Template"])]


class SequencerObject(object):
    def __init__(self):
        self.counter = 0
        self.todos = []

    def get(self, id):
        for ob in self.todos:
            if ob['id'] == id:
                return ob

    def create(self, data):
        ob = data
        ob['id'] = self.counter = self.counter + 1
        self.todos.append(ob)
        return ob

    def update(self, id, data):
        ob = self.get(id)
        ob.update(data)
        return ob

    def delete(self, id):
        ob = self.get(id)
        self.todos.remove(ob)
