# Queue JSON interface.
# (C) 2012 Petr Kubanek, Institute of Physics
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA


# from . import rtsapi
import datetime
from .rts2_wwwapi import rts2comm
# from . import iso8601
# from . import target
from .sotargets import so_target
import time
# import xml.dom.minidom

QUEUE_FIFO                   = 0
QUEUE_CIRCULAR               = 1
QUEUE_HIGHEST                = 2
QUEUE_WESTEAST               = 3
QUEUE_WESTEAST_MERIDIAN      = 4
QUEUE_SET_TIMES              = 5

def _nanNone(num):
    return 'nan' if (num is None) else num 

def _xmlQueueBoolAttribute(value):
    return 'true' if value else 'false'

def _getXmlBoolAttribute(node,name):
    return node.getAttribute(name) == 'true'

class QueueEntry:
    """Single queue entry. Provides methods to work on entry (observation request) level."""
    def __init__(self, jsonProxy, id, start, end, qid):
        self.jsonProxy = jsonProxy
        self.id = id
        self.__start = self.__end = None
        self.qid = qid
        self.target = None

        self.set_start(start)
        self.set_end(end)

    def from_xml(self,el):
        start = el.getAttribute('start')
        if len(start)>0:
            self.set_start(iso8601.ctime(start))
        end = el.getAttribute('end')
        if len(end)>0:
            self.set_end(iso8601.ctime(end))

    def get_target(self):
        """Return target object associated with the queue."""
        if self.target is None:
            self.target = target.Target(self.id)
            self.target.reload()
        return self.target

    def get_xmlnode(self,document):
        def localstr(t):
            return time.strftime('%Y-%m-%dL%H:%M:%S %Z', time.localtime(t))
        cm = ''
        if self.get_start() is not None:
            cm = ' localstart=' + localstr(self.get_start()) + ' '
        if self.get_end() is not None:
            cm += 'localend=' + localstr(self.get_end()) + ' '
        cel = None
        if cm:
            cel = document.createComment(cm)

        en = document.createElement('queueEntry')
        en.setAttribute('id', str(self.id))

        en.setAttribute('name', self.get_target().name)
        if self.get_start() is not None:
            en.setAttribute('start', iso8601.str(self.get_start()))
        if self.get_end() is not None:
            en.setAttribute('end', iso8601.str(self.get_end()))
        return (cel, en)

    def get_start(self):
        return self.__start

    def get_end(self):
        return self.__end

    def set_start(self, start):
        self.__start = start

    def set_end(self, end):
        self.__end = end

class Queue:
    """Queue abstraction. Provides methods for operation on the queue."""
    def __init__(self, name,service="SEL",queueType=QueueEntry):
        """Create new queue. Service parameters specify RTS2 service name. Optional queueType allow
        user to overwrite QueueEntry elements created for queue entries."""
        self.name = name
        self.jsonProxy = rts2comm()
        self.service = service
        self.entries = []
        self.queueing = None
        self.window = None
        self.skip_below = True
        self.test_constr = True
        self.remove_executed = True
        self.queueType = queueType

        if service is None:
            self.service = self.jsonProxy.getDevicesByType(rtsapi.DEVICE_TYPE_SELECTOR)[0]

    def clear(self):
        """Clear the queue."""
        self.jsonProxy.executeCommand(self.service,'clear {0}'.format(self.name))

    def load(self):
        """Refresh queue from server."""
        self.jsonProxy.refresh(self.service)

        self.window = self.jsonProxy.getValue(self.service, self.name + '_window')

        self.queueing = self.jsonProxy.getValue(self.service, self.name + '_queing')
        self.skip_below = self.jsonProxy.getValue(self.service, self.name + '_skip_below')
        self.test_constr = self.jsonProxy.getValue(self.service, self.name + '_test_constr')
        self.remove_executed = self.jsonProxy.getValue(self.service, self.name + '_remove_executed')

        ids = self.jsonProxy.getValue(self.service,self.name + '_ids')
        start = self.jsonProxy.getValue(self.service,self.name + '_start')
        end = self.jsonProxy.getValue(self.service,self.name + '_end')
        qid = self.jsonProxy.getValue(self.service,self.name + '_qid')

        self.entries = []

        for i in range(0,len(ids)):
            self.entries.append(self.queueType(self.jsonProxy, ids[i], start[i], end[i], qid[i]))

    def save(self, clear=False, remove_new=False):
        """Save queue settings to the server."""
        if clear:
            self.clear()

        self.jsonProxy.setValues({
            '{0}_window'.format(self.name):_nanNone(self.window),
            '{0}_skip_below'.format(self.name):self.skip_below,
            '{0}_test_constr'.format(self.name):self.test_constr,
            '{0}_remove_executed'.format(self.name):self.remove_executed,
            '{0}_queing'.format(self.name):self.queueing
        },device=self.service)
        queue_cmd = ''
        if clear:
            for x in self.entries:
                queue_cmd += ' {0} {1} {2}'.format(x.id, _nanNone(x.get_start()), _nanNone(x.get_end()))
            self.jsonProxy.executeCommand(self.service,'queue_at {0}{1}'.format(self.name, queue_cmd))
        else:
            for x in self.entries:
                queue_cmd += ' {0} {1} {2} {3}'.format(-1 if x.qid is None else x.qid, x.id, _nanNone(x.get_start()), _nanNone(x.get_end()))

            if remove_new:
                self.entries = [x for x in self.entries if x.qid > 0]

                self.jsonProxy.executeCommand(self.service,'queue_qids {0}{1}'.format(self.name, queue_cmd))
                print(self.service,'queue_qids {0}{1}'.format(self.name, queue_cmd))


    def add_target(self,id,start=None,end=None,nrep=None,separation=None):
        """Add target to queue."""
        self.jsonProxy.executeCommand(self.service,'queue_at_nrep {0} {1} {2} {3} {4} {5}'.format(self.name, id, _nanNone(start), _nanNone(end), -1 if nrep is None else nrep,_nanNone(separation)))

    def get_XMLdoc(self):
        """Serialize queue to XML document."""
        document = xml.dom.minidom.getDOMImplementation().createDocument('http://rts2.org','queue',None)
        self.to_xml(document,document.documentElement)
        return document

    def to_xml(self,document,node):
        node.setAttribute('window', str(self.window))
        node.setAttribute('skip_below', _xmlQueueBoolAttribute(self.skip_below))
        node.setAttribute('test_constr', _xmlQueueBoolAttribute(self.test_constr))
        node.setAttribute('remove_executed', _xmlQueueBoolAttribute(self.remove_executed))
        node.setAttribute('queueing', str(self.queueing))

        def appendEntry(x):
            cel,en = x.get_xmlnode(document)
            if cel:
                node.appendChild(cel)
            node.appendChild(en)

        list([appendEntry(x) for x in self.entries])

    def from_xml(self,node):
        """Construct queue from XML representation."""
        try:
            self.window = float(node.getAttribute('window'))
        except ValueError as ve:
            self.window = None
        self.skip_below = _getXmlBoolAttribute(node, 'skip_below')
        self.test_constr = _getXmlBoolAttribute(node, 'test_constr')
        self.remove_executed = _getXmlBoolAttribute(node, 'remove_executed')
        self.queueing = int(node.getAttribute('queueing'))

        for el in node.getElementsByTagName('queueEntry'):
            q = self.queueType(self.jsonProxy, el.getAttribute('id'), None, None, None)
            q.from_xml(el)
            self.entries.append(q)

    def load_xml(self,f):
        document = xml.dom.minidom.parse(f)
        self.from_xml(document.documentElement)

    def __str__(self):
        if len(self.entries):
            ids = [str(q.id) for q in self.entries]
            return ' '.join(ids)
        return 'empty'

def load_xml(filename, queues=None):
    """Load ques from XML file. Queues parameter can specify name of queue(s) to fill in."""
    f = open(filename, 'r')
    document = xml.dom.minidom.parse(f)
    f.close()

    for qu in document.documentElement.getElementsByTagName('queue'):
        qname = qu.getAttribute('name')
        if queues is not None and not(qname in queues):
            continue
