#! /usr/bin/env python
# Script that process stdout from pcf and creates IRI messages
#
# Copyright (C) 2014 Martin Holkovic
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program 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 General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import socket
import sys
import json
import time
import string
import inspect
import signal
from types import *
from parser_functions import *

interfacesG = ""
protocolsG = ""
rerunG = ""
s = None
PARSER_MAX_RECV = 1024  


def lineno():
    return inspect.currentframe().f_back.f_lineno


def handler(signum, frame):
    parser_disconnect()
    sys.exit(0)


def parser_message_length(data):
    offset = 0
    length = 0
    try:
        while data[offset] != "[": # prechadzam az po konec cislic
            length = length * 10 + int(data[offset])
            offset = offset + 1
    except:
        print >> sys.stderr,  data
        #sys.exit()
    return offset, length


def parser_connect_socket():
    global s
    connected = False
    while connected == False:
        if s != None: # ked sa jedna o reconnect stary socket zavrem
            s.close()
        time.sleep(0.2)
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            port = get_running_port()
            while port == "": # treba spustit parser
                os.system("sudo python " + parserMainFilename + " start &")
                time.sleep(0.3)
                port = get_running_port()
            s.connect(('localhost', int(port)))
            
            s.sendall(interfacesG) # odeslani zeznamu rozhrani
            reply = s.recv(256) # cekani na potvrdeni
            s.sendall(protocolsG) # odeslani zeznamu protokolu
            reply = s.recv(256) # cekani na potvrdeni
            s.sendall(rerunG) # odeslani parametre spusteni
            
            print >> sys.stderr,  "Connected to port:" + port
            connected = True
        except:
            pass
    


def parser_connect(interfaces, protocols, argv):
    global interfacesG, protocolsG, rerunG
    
    signal.signal(signal.SIGTERM, handler)
    
    interfacesG = interfaces
    protocolsG = protocols
    
    if type(argv) is ListType:
        for arg in argv:
            rerunG = rerunG + " " + arg
    
    parser_connect_socket()


def parser_recv():
    global s
    try:
        data = None
        
        while True:
            data = s.recv(PARSER_MAX_RECV)
            if len(data) == 0: # spadel server
                print >> sys.stderr,  "Server is unexpectly down."
                parser_connect_socket(s) # reconnect
            elif data == "Bye":
                print >> sys.stderr,  "Server send 'Bye' message."
                return ""
            else:
                return data
        
    except KeyboardInterrupt:
        return "" # pri reconecte sa zmeni hodnota


def parser_read(call_function):
    global s
    try:
        state = 0 # stav citania spravy
        while True:
            if state == 0: # buffer je prazdny
                data = parser_recv()
                if data == "": # ukonceni programu
                    return
                offset, length = parser_message_length(data)
                if offset+length <= len(data): # v buffery je cela sprava
                    decoded = json.loads(data[offset:offset+length])
                    call_function(decoded[0], decoded[1], decoded[2]["data"])
                    if offset+length < len(data): # v buffery je vic nez 1 sprava
                        state = 2 # v buffery je este dalsi sprava
                else: # v buffery neni cela sprava
                    backup = data
                    state = 1 # do bufferu sa nezmestila cela sprava
            elif state == 1: # do bufferu sa nezmestila cela sprava
                data = parser_recv()
                if data == "": # ukonceni programu
                    return
                data = backup + data
                offset, length = parser_message_length(data) # v pripade skoku ze stavu 2 je to nutne
                if offset+length <= len(data): # v buffery je cela sprava
                    try:
                        decoded = json.loads(data[offset:offset+length])
                    except:
                        print >> sys.stderr,  data
                        print >> sys.stderr,  data[offset:offset+length]
                        sys.exit()
                    call_function(decoded[0], decoded[1], decoded[2]["data"])
                    if offset+length < len(data): # v buffery je vic nez 1 sprava
                        state = 2 # v buffery je este dalsi sprava
                    else:
                        state = 0 # buffer je prazdny
                else: # v buffery neni cela sprava
                    backup = data
            elif state == 2: # v buffery je este dalsi sprava
                data = data[offset+length:]
                if len(data) < 24: # je mozne ze sa nezmestila cela dlzka spravy, 24 = minimalna dlzka spravy
                    backup = data
                    state = 1
                    #print "TEST"
                    #print data
                else: # druha sprava obsahuje celu informaciu o dlzke
                    offset, length = parser_message_length(data)
                    if offset+length <= len(data): # v buffery je cela sprava
                        decoded = json.loads(data[offset:offset+length])
                        call_function(decoded[0], decoded[1], decoded[2]["data"])
                        if offset+length < len(data): # v buffery je vic nez 1 sprava
                            state = 2 # v buffery je este dalsi sprava
                        else: # v buffery neni vic sprav
                            state = 0 # buffer je prazdny
                    else: # v buffery neni cela sprava
                        backup = data
                        state = 1 # do bufferu sa nezmestila cela sprava
    #except:
    #    return s
    except KeyboardInterrupt:
        pass


def parser_disconnect():
    global s
    try:
        message = "Bye"
        s.sendall(message)
        print >> sys.stderr,  message
    except:
        pass
    s.close()
