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

# System modules
import telnetlib
import sys
import requests
from urllib.parse import urlencode
import re

# custom modules
from utils.logger import log
from devices import check

class OpenTSI:
    def __init__(self, url):
        self.url = url.split(":")[0] or "localhost"
        self.port =  url.split(":")[1] or 22
        self.timeout = 3
        self.error = None

    @check.telnet_errors
    def connect(self):
        tn = telnetlib.Telnet(self.url, self.port, timeout=3)
        return tn

    @check.telnet_errors
    def get(self, message=None):
        """
        Connect to the cabinet
        """

        # Login data for cabinet communication.
        # It is a byte-string.
        auth = b'auth plain "admin" "admin"\n'

        # Send the message. it can be a string (even a multi-line
        # string), or a list of strings

        if type(message) is str:
            # Maybe is multi-line
            msglist = message.split("\n")
            # Removing empty elements
            msglist = [x for x in msglist if x]
        elif type(message) is list:
            msglist = message

        # Transforming every string in "1 get string\n"
        msg = [f"{i+1} get {j}\n" for i,j in enumerate(msglist)]
        # From list to string, and byte-coded
        msg = bytes("".join(msg), "utf+8")

        # Connect to the cabinet.
        tn = self.connect()
        if not tn:
            return {"Error": self.error}

        tn.read_until(b"[ruder]\n")
        tn.write(auth)
        tn.read_until(b"AUTH OK 0 0\n")

        # Send the message.
        tn.write(msg)

        # For each command, the *asyncrhronous* answer contains:
        #
        # COMMAND OK
        # DATA INLINE ...
        # COMMAND COMPLETE
        #
        # Append all the buffer line by line to a list.

        tn_answer = []
        for i in range(msg.count(b"\n")*3-1):
            tn_answer.append(tn.read_until(b"\n"))

        # Close the cabinet connection.
        tn.close()

        # Keep only the data.
        tn_values = [s for s in tn_answer if b"DATA INLINE" in s]

        # Create a python dictionary with name and value.
        telnet_dict = dict([m[14:-1].decode().split("=") for m in tn_values])

        # Try transforming values to float.
        for k,v in telnet_dict.items():
            try:
                telnet_dict[k] = int(v)
            except:
                try:
                    telnet_dict[k] = float(v)
                except ValueError:
                    telnet_dict[k] = str(v)

        return(telnet_dict)


    @property
    def coordinates(self):
        """
        Ask simultaneously
        RA2000, DEC2000, ALT, AZ, LST, UTC.
        Answer is given as a dict of decimal numbers.
        UTC is given as unix time.
        """

        message = '''POSITION.EQUATORIAL.RA_J2000
        POSITION.EQUATORIAL.DEC_J2000
        POSITION.HORIZONTAL.alt
        POSITION.HORIZONTAL.az
        POSITION.LOCAL.SIDEREAL_TIME
        POSITION.LOCAL.UTC'''

        telnet_dict = self.get(message)

        # radec and altaz in lists as usual
        simple_dict = {
            "radec" : [telnet_dict["POSITION.EQUATORIAL.RA_J2000"],
                       telnet_dict["POSITION.EQUATORIAL.DEC_J2000"]],
            "altaz" : [telnet_dict["POSITION.HORIZONTAL.ALT"],
                       telnet_dict["POSITION.HORIZONTAL.AZ"]],
            "utc" : telnet_dict["POSITION.LOCAL.UTC"],
            "lst" : telnet_dict["POSITION.LOCAL.SIDEREAL_TIME"],
        }

        return simple_dict

    @property
    def utc(self):
        """
        in UNIX time
        """
        message = "POSITION.LOCAL.UTC"
        telnet_dict = self.get(message)
        return telnet_dict.get(message) or self.error

    def test1(self):
        message = "POSITION.EQUATORIAL.RA_J2000"
        return self.get(message)

    def test2(self):
        message = '''POSITION.EQUATORIAL.RA_J2000
        POSITION.EQUATORIAL.DEC_J2000
        POSITION.HORIZONTAL.alt
        POSITION.HORIZONTAL.az
        POSITION.LOCAL.SIDEREAL_TIME
        POSITION.LOCAL.UTC'''
        return self.get(message)

    def test3(self):
        message = ["POSITION.EQUATORIAL.RA_J2000",
                   "POSITION.EQUATORIAL.DEC_J2000",
                   "POSITION.HORIZONTAL.alt",
                   "POSITION.HORIZONTAL.az",
                   "POSITION.LOCAL.SIDEREAL_TIME",
                   "POSITION.LOCAL.UTC"]
        return self.get(message)
