#!/usr/bin/python
# ----------------------------------------------------------------------------------------------
# TODO
# Reverse Item from oldest to newest sorting on date
# Source selector from gpio button
# ----------------------------------------------------------------------------------------------
runs  = True
g_site = 0
g_urls = ""
# ----------------------------------------------------------------------------------------------
nam_1 = "Reuters"
snd_1 = "./sound/ReutersFeed.wav"
url_1 = "http://www.reuters.com/news/archive/topNews"
div_1 = "//div[@class='story-content']"
dat_1 = ".//span[@class='timestamp']"
tit_1 = ".//h3[@class='story-title']"
inf_1 = "./p"
xml_1 = False
# ----------------------------------------------------------------------------------------------
nam_2 = "AFP"
snd_2 = "./sound/AFPFeed.wav"
url_2 = "https://www.afp.com/en/news-hub"
div_2 = "//div[starts-with(@id,'afp_new')]"
dat_2 = "./div[@class]/span[@class]"
tit_2 = "./div[@class]/h4[starts-with(@class,'htitle')]/a"
inf_2 = "./div[@class]/div[starts-with(@class,'showt')]/p"
xml_2 = False
# ----------------------------------------------------------------------------------------------
nam_3 = "CERT-EU"
snd_3 = "./sound/CERTFeed.wav"
url_3 = "https://cert.europa.eu/rss?type=category&id=CERT-LatestNews&language=all&duplicates=false"
div_3 = "//item"
dat_3 = "./pubdate" 
tit_3 = "./title" 
inf_3 = "./description"  
xml_3 = True
# ----------------------------------------------------------------------------------------------
nam_4 = "TWITTER"
snd_4 = "./sound/TwitterFeed.wav"
url_4 = "https://twitter.com/realDonaldTrump"
div_4 = "//div[@class='content']"
dat_4 = "./div/small[@class='time']/a/span"
tit_4 = ".//p"
inf_4 = "./div//strong"
xml_4 = False
# ----------------------------------------------------------------------------------------------
g_nam = [nam_1,nam_2,nam_3,nam_4]
g_snd = [snd_1,snd_2,snd_3,snd_4]
g_url = [url_1,url_2,url_3,url_4]
g_div = [div_1,div_2,div_3,div_4]
g_dat = [dat_1,dat_2,dat_3,dat_4]
g_tit = [tit_1,tit_2,tit_3,tit_4]
g_inf = [inf_1,inf_2,inf_3,inf_4]
g_xml = [xml_1,xml_2,xml_3,xml_4]

# ==============================================================================================
# Config
# ----------------------------------------------------------------------------------------------
from ConfigParser import SafeConfigParser
def getConf():
    global g_site 
    global g_urls
    parser = SafeConfigParser()
    # -----------------------------------------------------------------------------------------
    try:
        parser.read('./config.ini')
    except:
        g_site=0
        g_urls="http://209.180.212.65:8000"
    # -----------------------------------------------------------------------------------------
    try:
        g_site=int(parser.get('Site_Index', 'index'))
        if (g_site<0) or (g_site>3):
            g_site=0
    except:
        g_site=0
    # -----------------------------------------------------------------------------------------
    try:
        g_urls=   (parser.get('Site_AFSK',  'url'))
    except:
        g_urls="http://209.180.212.65:8000"
    # -----------------------------------------------------------------------------------------
    print "INFO: Feed N." + str(g_site)
    print "INFO: AFSK " +       g_urls
    return

# ==============================================================================================
# Alternate FSK mode
# ----------------------------------------------------------------------------------------------
import RPi.GPIO as GPIO
# ----------------------------------------------------------------------------------------------
def shutdown(channel):
    global runs
    GPIO.remove_event_detect(22)
    runs=False
    os.system("aplay -q ./sound/Shutdown.wav")
    time.sleep(4)
    os.system("sync;sync;halt")
    while 1:
        time.sleep(1)
# ----------------------------------------------------------------------------------------------
def otherMode():
    GPIO.setmode(GPIO.BCM)
    # ------------------------------------------------------------------------------------------
    GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.add_event_detect(17, GPIO.FALLING, callback=shutdown, bouncetime=200)
    # ------------------------------------------------------------------------------------------
    GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    if (GPIO.input(22)):
        os.system("aplay -q ./sound/RaspberryTTY.wav");
        time.sleep(4)
        os.system("aplay -q ./sound/FSKMode.wav")
        while runs:
            os.system("omxplayer "+g_urls)
            time.sleep(10)
        sys.exit(2)
    return

# ==============================================================================================
# Serial Process
# ----------------------------------------------------------------------------------------------
import serial
# ----------------------------------------------------------------------------------------------
def toSerial(port,data):
    try:
	ser = serial.Serial(port,50)
        ser.bytesize = serial.FIVEBITS
        ser.parity   = serial.PARITY_NONE
        ser.stopbits = serial.STOPBITS_ONE_POINT_FIVE
        ser.write(data)
        ser.flush()
        ser.close()
    except:
        print "ERROR: SERIAL ACCESS"
        os.system("aplay -q ./sound/NoSerial.wav")
    return

# ==============================================================================================
# ITA2 Process
# ----------------------------------------------------------------------------------------------
FIGS = 0x1b
LTRS = 0x1f
# ----------------------------------------------------------------------------------------------
#           ' ' ,'!' ,'"' ,'#' ,'$' ,'%' ,'&' ,'\'' ,'(',')' ,'*' ,'+' ,',' ,'-' ,'.' ,'/' ,
#           '0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,':' ,';' ,'<' ,'=' ,'>' ,'?' ,
#           '@' ,'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,
#           'P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y' ,'Z' ,'[' ,'\\',']' ,'^' ,'_' ,
#           '`' ,'a' ,'b' ,'c' ,'d' ,'e' ,'f' ,'g' ,'h' ,'i' ,'j' ,'k' ,'l' ,'m' ,'n' ,'o' ,
#           'p' ,'q' ,'r ','s' ,'t' ,'u' ,'v' ,'w' ,'x' ,'y' ,'z' ,'{' ,'|' ,'}' ,'~' ,' '
# ----------------------------------------------------------------------------------------------
TranspUS = [0x04,0x8D,0x91,0x00,0x89,0x00,0x9A,0x85,0x8F,0x92,0x00,0x91,0x8C,0x83,0x9C,0x9D,
            0x96,0x97,0x93,0x81,0x8A,0x90,0x95,0x87,0x86,0x98,0x8E,0x9E,0x8F,0x00,0x92,0x99,
            0x00,0x03,0x19,0x0E,0x09,0x01,0x0D,0x1A,0x14,0x06,0x0B,0x0F,0x12,0x1C,0x0C,0x18,
            0x16,0x17,0x0A,0x05,0x10,0x07,0x1E,0x13,0x1D,0x15,0x11,0x8F,0x9D,0x92,0x00,0x83,
            0x8B,0x03,0x19,0x0E,0x09,0x01,0x0D,0x1A,0x14,0x06,0x0B,0x0F,0x12,0x1C,0x0C,0x18,
            0x16,0x17,0x0A,0x05,0x10,0x07,0x1E,0x13,0x1D,0x15,0x11,0x8F,0x00,0x92,0x00,0x00]
# ----------------------------------------------------------------------------------------------
def toITA2(text):
    # ------------------------------------------------------------------------------------------
    ita2 = chr(LTRS)
    letter = 1
    # ------------------------------------------------------------------------------------------
    for char in text:
        # --------------------------------------------------------------------------------------
        # Old mechanical machines need time to complete CR / LF so adding a NULL
        # --------------------------------------------------------------------------------------
        if (char == '\n'):
                ita2+=chr(0x02)+chr(0x00)+chr(0x00)
        if (char == '\r'):
                ita2+=chr(0x08)+chr(0x00)
        # --------------------------------------------------------------------------------------
        # Taking care of the LETTER/FIGURE changes
        # --------------------------------------------------------------------------------------
        if (ord(char) >= 0x20) and (ord(char) <= 0x7F):
                tmp = TranspUS[ord(char)-0x20]
                if (tmp< 0x80) and (letter == 0):
                       ita2+=chr(LTRS)
                       letter=1
                if (tmp>=0x80) and (letter == 1):
                        ita2+=chr(FIGS)
                        letter=0
                        tmp-=0x80;
                ita2+=chr(tmp)
    # ------------------------------------------------------------------------------------------
    return ita2

# ==============================================================================================
# Clean a line by removing unicode,  space and returns
# ----------------------------------------------------------------------------------------------
def cleanline(line):
    if (line!=""):
        line=line.encode('ascii', 'ignore').decode()
        line=line.replace("\n", "")
        line=line.strip()

    return line

# ==============================================================================================
# Read and process a page
# ----------------------------------------------------------------------------------------------
import re
import urllib
from lxml import html
from lxml.html.clean import clean_html
# ----------------------------------------------------------------------------------------------
line_max  = str(64)
# ----------------------------------------------------------------------------------------------
def readpage(xurl,xnam,xdiv,xdat,xtit,xinf,xxml,dict):
    first= True
    text = ""
    # ------------------------------------------------------------------------------------------
    try:
        page = html.fromstring(urllib.urlopen(xurl).read())
    except:
        print "ERROR: PAGE LOAD"
        text="Error loading page"
        os.system("aplay -q ./sound/NoConnection.wav")
        return text
    # ------------------------------------------------------------------------------------------
    try:
        if (not xxml):
            page=clean_html(page)
        for element in page.xpath(xdiv):
            #-----------------------------------------------------------------------------------
            # Title will be used an already seen key
            #-----------------------------------------------------------------------------------
            for title in element.xpath(xtit):
                #-------------------------------------------------------------------------------
		# Here titles MUST differ between two items (not the case with twitter...)
                #-------------------------------------------------------------------------------
		ctit=cleanline(title.text_content())
               #hsh=hash(ctit)
                hsh=ctit
                #-------------------------------------------------------------------------------
                # Already processed : reset count to 2
                #-------------------------------------------------------------------------------
		if hsh in dict:
	            first=False
                    dict[hsh]=2
                #-------------------------------------------------------------------------------
                # First seen : set count to 2 and process
                #-------------------------------------------------------------------------------
                else:
                    dict[hsh]=2
                    ctit = re.sub("(.{"+line_max+"})", "\\1\r\n", ctit, 0, re.DOTALL)
            #-----------------------------------------------------------------------------------
            # First seen: process next items
            #-----------------------------------------------------------------------------------
            if (first):
		if (xdat!=""):
                   for date  in element.xpath(xdat):
		      cdat = cleanline(date.text)
		if (xinf!=""):
                   for infos in element.xpath(xinf):
		      cinf = re.sub("(.{"+line_max+"})", "\\1\r\n", cleanline(infos.text_content()), 0, re.DOTALL)
            #-----------------------------------------------------------------------------------
            # First seen: assemble items
            #-----------------------------------------------------------------------------------
            if (first):
                text+='----\r\n'
                text+=xnam+" - "+cdat
                text+='\r\n'
                text+=ctit
                text+='\r\n'
                text+=cinf
                text+='\r\n'
    except:
        print "ERROR: PAGE PORCESSING"
    return text
# ==============================================================================================
# clean Dictionnary: delete any entrie whose use count is zero (were not refreshed)
# ----------------------------------------------------------------------------------------------
def cleanDict(dict):
    try:
        old={}
        for key in dict:
            dict[key]-=1
            if (dict[key]==0):
                print "WARN: DELETE "+str(key)
                old[key]="D"
        for key in old:
            dict.pop(key)
    except:
        print "ERROR: DICT"
    return

# ==============================================================================================
# Main
# ----------------------------------------------------------------------------------------------
import sys, getopt
import time
import os;
from   sys import platform
# ----------------------------------------------------------------------------------------------
def main(argv):
    # ------------------------------------------------------------------------------------------
    # Debug mode
    # ------------------------------------------------------------------------------------------
    try:
        opts,args = getopt.getopt(argv[1:],"dt",["debug","testing"])
    except:
        print 'service.py {-d|--debug}{-t|--testing}'
        sys.exit(2)
    # ------------------------------------------------------------------------------------------
    debug=  False
    testing=False
    for opt,arg in opts:
       if opt in ("-d","--debug"):
            debug  =True
       if opt in ("-t","--testing"):
            testing=True
    # -----------------------------------------------------------------------------------------
    # Get system information
    # -----------------------------------------------------------------------------------------
    syst=platform.lower()
    s_port = "NONE"
    if "win"     in syst:
        s_port = "COM1"
    if "linux" or "freebsd" in syst:
        s_port = "/dev/serial0"
    # ------------------------------------------------------------------------------------------
    # Try to open and default to classic ASCII output if no serial is there
    # ------------------------------------------------------------------------------------------
    try:
        ser = serial.Serial(s_port,50)
        ser.close()
    except:
        s_port = "NONE"
        if (not debug) and (not testing):
            print "ERROR: NO SERIAL"
            os.system("aplay -q ./sound/NoSerial.wav")
    # ------------------------------------------------------------------------------------------
    # Get conf
    # ------------------------------------------------------------------------------------------
    getConf()
    # ------------------------------------------------------------------------------------------
    # Run other modes
    # ------------------------------------------------------------------------------------------
    otherMode()
    # ------------------------------------------------------------------------------------------
    # Defaut tty mode
    # ------------------------------------------------------------------------------------------
    os.system("aplay -q ./sound/RaspberryTTY.wav");
    time.sleep(4)
    os.system("aplay -q ./sound/DirectMode.wav");
    # ------------------------------------------------------------------------------------------
    # Send NULL to awake machine and start at a new line
    # ------------------------------------------------------------------------------------------
    if (s_port!="NONE") and (not debug):
        toSerial(s_port,chr(0x00)+chr(0x00))
        toSerial(s_port,toITA2("\r\n"))
        toSerial(s_port,toITA2("RaspTTY (C) RxControl"))
        toSerial(s_port,toITA2("\r\n"))
    # ------------------------------------------------------------------------------------------
    # Runs testing
    # ------------------------------------------------------------------------------------------
    if (testing):
        txt1="the quick brown fox jumps over the lazy dog 0123456789"
        txt2="voyez ce brick geant que j'examine pres du wharf 01234567890"
        txt=[txt1,txt2]
        for t in txt:
            if (s_port!="NONE") and (not debug):
                toSerial(s_port,toITA2(t))
		toSerial(s_port,toITA2("\r\n"))
            else:
                print t
        sys.exit(2) 
    # ------------------------------------------------------------------------------------------
    i_dict = {}
    # ------------------------------------------------------------------------------------------
    os.system("aplay -q "+g_snd[g_site]);
    while runs:
        # --------------------------------------------------------------------------------------
        # Read page and get new items
        # --------------------------------------------------------------------------------------
        text=readpage(g_url[g_site],g_nam[g_site],g_div[g_site],g_dat[g_site],g_tit[g_site],g_inf[g_site],g_xml[g_site],i_dict)
        # --------------------------------------------------------------------------------------
        # Clean dictionnary from old items
        # --------------------------------------------------------------------------------------
        cleanDict(i_dict)
        # --------------------------------------------------------------------------------------
        # ITA2 Process
        # --------------------------------------------------------------------------------------
	if (text!=""):
            if (s_port!="NONE") and (not debug):
                toSerial(s_port,chr(0x00)+chr(0x00))
                text = toITA2(text)
                toSerial(s_port,text)
            else:
                print text
        # --------------------------------------------------------------------------------------
        time.sleep(60)
        # --------------------------------------------------------------------------------------
# ==============================================================================================
#
# ----------------------------------------------------------------------------------------------
if __name__ == "__main__":
    main(sys.argv)
# ----------------------------------------------------------------------------------------------

