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


#!!!!!------------------------------------!!!!!
#    Execute this in "su", or it won't work
#!!!!!------------------------------------!!!!!


#<<<<<startInit>>>>>
#for Displaying; show some frames
#the size of buttons, panels,and frames are manually controlled
import wx
#for GPIO(requiers sudo)
import RPi.GPIO as GPIO
#for showing movies
from omxplayer import OMXPlayer
#for sleep/time managing(time has sleep)
import time
#for Picture
#from PIL import Image
#for shutdown
import os
import sys
#for read csv files
import csv
#import pandas as pd
#for communication
from datetime import datetime
#for threading
import threading
import wx.lib.newevent
#<<<<<endInit>>>>>

#<<<<<startSetValues>>>>>
movAfterDictionary='dictMA.csv'
signalPictureDictionary='dictSP.csv'

movName="forteskey"

dictMA={}
dictSP={}
dictAM={}
dictPS={}

ingList=[]

#<<startCalcRelativePath>>
def relPath(pathpath):
    absoPath= os.path.dirname(os.path.abspath(__file__))
    os.path.normpath(os.path.join(absoPath,pathpath))
#<<endCalcRelativePath>>
#<<<<<endSetValues>>>>>


#<<<<<startCommunication>>>>>
class Com:
    #定数（ではないけど）定義（単位はsec)(ms以下は必ず小数指定)
    ON_USEC = 0.02
    OFF_USEC = 0.06
    STOP_USEC = 0.1
    READ_USEC = 0.1
    HIGH_USEC = 0.04

    SndPinNo  = 33
    RcvPinNo = 32 #上面オレンジ線
    RcvPinNo2 = 40 #下面ホワイト線
    def __init__(self):
        #<<<<<GPIOsettings>>>>>
        #GPIO.cleanup()
        GPIO.setmode(GPIO.BOARD)
        #送信ピンの設定
        GPIO.setup(self.SndPinNo,GPIO.OUT)
        #受信ピンの設定
        GPIO.setup(self.RcvPinNo,GPIO.IN)
        GPIO.setup(self.RcvPinNo2,GPIO.IN)
    
    #パルスでは無いが名前そのまま
    #引数（秒）だけHIGH出力する
    #秒以下は少数指定
    def PalseHigh(self,cnt):
        GPIO.output(self.SndPinNo, GPIO.HIGH)
        time.sleep(cnt)
        GPIO.output(self.SndPinNo,GPIO.LOW)

#データチェック
    def DataCheck(self,dt):
        key1 = 0
        key2 = 0
            
        #キーデータ１のチェック
        for n in range(8):
            if dt[n] == 1:
                key1 += 2**n
                print "key1 = ",key1
            
        #キーデータ２のチェック
        for n in range(8):
            if dt[n+8] == 0:
                key2 += 2**n
                print "key2 = ",key2
            
        if key1 != key2:
            return 0
        else:
            return key1
    
    #送信用メソッド
    def Send(self,KeyCode):
        print "send: [",KeyCode,"]"
        #リーダ部を送る
        self.PalseHigh(0.5)
        time.sleep(self.READ_USEC)
        #キーデータ１を送る
        for n in range(8):
            self.PalseHigh(self.HIGH_USEC)
            if (KeyCode >> n) & 0x01:
                time.sleep(self.ON_USEC)
            else:
                time.sleep(self.OFF_USEC)
        #キーデータ１を反転して送る(確認用）
        for n in range(8):
            self.PalseHigh(self.HIGH_USEC)
            if (KeyCode >> n) & 0x01:
                time.sleep(self.OFF_USEC)
            else:
                time.sleep(self.ON_USEC)
        #ストップデータを送る
        self.PalseHigh(self.HIGH_USEC)
        time.sleep(self.STOP_USEC)
    
    #受信用メソッド
    def Receive(self):
        ans = 0
        t = 0
        IRbit = []
        #リーダ部のチェックを行う
        if GPIO.input(self.RcvPinNo)==1:
            print "signal recognized"
            t1 = datetime.now()
            while GPIO.input(self.RcvPinNo)==1:
                1#while文を書くため。意味は無い。書かなくても済むなら教えて。
            t2 = datetime.now()
            diff = t2 - t1
            t = diff.microseconds/1000
        if t >= 450: #450msでリーダ部判定
            print "Reader on"
            while GPIO.input(self.RcvPinNo) ==0: #リーダ部を読み飛ばす
                1
            i = 0
            while True:
                while GPIO.input(self.RcvPinNo) ==1: #OFF部を読み飛ばす
                    1
                t1 = datetime.now()
                while GPIO.input(self.RcvPinNo) ==0:
                    1
                t2 = datetime.now()
                diff = t2 - t1
                t = diff.microseconds/1000
                if t >= 40:
                    IRbit.append(0)
                else:
                    IRbit.append(1)
                i += 1
                if i == 16: #2バイト読み込んだら終了
                    break
            print IRbit
            
            if i == 16:
                print "check start"
                ans = self.DataCheck(IRbit)
            return ans
#<<<<<endCommunication>>>>>


com=Com()

#スレッドにする。
class RecThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self,group=None,target=self.thread_target)
        self.lock = threading.Lock()
        self._cancel = False
        self.recData=0
        self.forTesCount=0#loopTest
    def thread_target(self):
        while True:
            self.recData=com.Receive()
            #ここに受け取ったデータ: recDataをphantomからrealに変換し、
            #real側でくっつけて、返すものが求められる
            if (self.recData != 0 and self.recData is not None):
                #<Merge>
                global movName
                movName=dictSP[str(self.recData)]+"-"+movName
                if os.path.exists("movs/"+movName+".mp4") is False:
                    movName="NA"
                #<Playing>
                print "startPlay"
                player = OMXPlayer("movs/"+movName+".mp4")
                player.play()
                time.sleep(player.duration()-5)
                com.Send(int(dictPS.get(dictMA.get(movName,"NA"),"0")))
                time.sleep(5)
                #player.pause()
                #if you got to quit you can't re-open
                player.quit()
                print "endPlay"
            #このあとに静止画を表示するなら、dictMA[movName]
            #<loopTest
            self.forTesCount+=1
            if self.forTesCount%1000 == 0:
                print "recNOW"
            #loopTest>
            time.sleep(0.01)


ReceiveTh = RecThread()
#endCommunicationAvailable



#<<<<<startDictInit>>>>>
#<<Conv movName->moviePath>>
#<alter: NoDict>
if os.path.exists(movAfterDictionary) is False:
    with open(movAfterDictionary,'ab') as tempMAmak:
        #'a' means: make file unless it's already exist
        #'b' also has some meaning and you should use, but i don't know about that
        writer=csv.writer(tempMAmak,lineterminator='\n')
        writer.writerow(["forteskeyNext","ForTes"])
    print "N/Exist/dict: dictMA"
#<read the Dict>
with open(movAfterDictionary,'rb') as tempMA:
    tempMAdict=csv.reader(tempMA)
    for rowMA in tempMAdict:
        dictMA[rowMA[0]]=rowMA[1]
        dictAM[rowMA[1]]=rowMA[0]

#<<Conv phantomData->movName>>
#<alter: NoDict>
if os.path.exists(signalPictureDictionary) is False:
    with open(signalPictureDictionary,'ab') as tempSPmak:
        writerC=csv.writer(tempSPmak,lineterminator='\n')
        writerC.writerows([[1,"forteskey"],[2,"Next"]])
    print "N/Exist/dict: dictSP"
#<read the Dict>
with open(signalPictureDictionary,'rb') as tempSP:
    tempSPdict=csv.reader(tempSP)
    for rowSP in tempSPdict:
        dictSP[rowSP[0]]=rowSP[1]
        dictPS[rowSP[1]]=rowSP[0]
        ingList.append(rowSP[1])
#<<<<<endDictInit>>>>>
print "<MA!"
print dictMA
print "!MA>"
print "<SP!"
print dictSP
print "!SP>"

##when you need to chage values of globalVariables, use global like this:
#global VarVar
#VarVar=something
##while you just "use", global is not necessary

#<<<<<startButtonEvents>>>>>
#<<<startStartEvent>>>
def StartClick(event):#It's a triger.
    print "start START"
    with ReceiveTh.lock:
        com.Send(int(dictPS.get(movName,"0")))
    print "end START"
#<<<endStartEvent>>>

#<<<startMenuEvent>>>
def MenuClick(event):
    #wxでフレーム出すときに必要なやつ
    MenuApp = wx.App()
    
    #frameを定義して、作ったフレームを代入
    global MenuSortFrame
    MenuSortFrame = MenuSortList()
    
    #中央に表示
    #MenuSortFrame.Centre()
    MenuSortFrame.Center()
    MenuSortFrame.Show()
    
    #フレームを出すときに最後に書くやつ
    MenuApp.MainLoop()
#<<<endMenuEvent>>>

def ResetClick(event):
    global movName
    movName=""
    global MainFrame
    MainFrame.Close()
    MainApp = wx.App()
    MainFrame = CFrame()
    MainFrame.Center()
    MainFrame.Show()
    MainApp.MainLoop()
def PowerOffClick(event):
    global MainFrame
    MainFrame.Close()
    #Close won't work now
    #Available below row, and system will be shuted down.
    #maybe we should show some confirmation
    os.system("sudo shutdown -h now")
    sys.exit()
#<<<<<endButtonEvents>>>>>


#<<<<<startListEvents(in Menu)>>>>>NeedToEdit
#一つ目のリストのイベント設定（分類の選択用）
def MenuSortListBox(event):
    #押した選択肢を呼び出して代入
    obj = event.GetEventObject()
    if obj.GetClientData(obj.GetSelection()) != u"" and obj.GetClientData(obj.GetSelection()) is not None:
        bunrui=obj.GetClientData(obj.GetSelection())

    #startSort(needToBranch)
    print "<SortLevel: ",bunrui,"; SL>"
    
    MenuIngApp = wx.App()
    global MenuIngFrame
    MenuIngFrame = MenuIngList(bunrui)
    MenuIngFrame.Center()
    MenuIngFrame.Show()
    MenuIngApp.MainLoop()

#二つ目のリストのイベント設定（物質の選択用）
def MenuIngListBox(event):
    obj=event.GetEventObject()
    #movNameへの代入
    #なぜか、選択時に何も持っていない状態でもう一度ここを通りに来るので、それを弾くためにいかが指定されている。
    global movName
    if obj.GetStringSelection() != u"" and obj.GetStringSelection() is not None:
        movName=obj.GetStringSelection()
    print "Chk(movName at menu): "
    print movName
    #日本語化の暁には以下。
    #movName=obj.GetClientData(obj.Getselection())

    #出ている三つのフレームをすべて消す＞＞できればfallere2の研究を取り込み、Main以外を消去mainでは更新をしたい
    global MainFrame
    global MenuIngFrame
    global MenuSortFrame
    MenuSortFrame.Close()
    MenuIngFrame.Close()
    MainFrame.Close()
    
    #ボタン四つの画面を再度表示（movNameを元にBranchさせる（CFrame内で処理））
    MainApp = wx.App()
    MainFrame = CFrame()
    MainFrame.Center()
    MainFrame.Show()
    MainApp.MainLoop()
#<<<<<endListEvents(in Menu)>>>>>


#<<<<<startDefineLists(in Menu)>>>>>
#一つ目のリスト（分類の選択用）の定義(だいたいこれと似たような感じ)
class MenuSortList(wx.Frame):
    def __init__(self):
        #フレームを定義（testはフレームの上部に出る名前）
        wx.Frame.__init__(self,None, wx.ID_ANY, u"Sort", size=(350,350))
        
        #パネルを定義
        panel = wx.Panel(self, wx.ID_ANY)
        #パネルの色を設定
        panel.SetBackgroundColour("#AFAFAF")
        
        #表示される要素を定義、ここは元来決まっているものを表示すれば良い。英語版
        #element_array = ("element_1", "element_2", "element_3", "element_4")
        #SortListBox = wx.ListBox(panel, wx.ID_ANY, size=(400,400), choices=element_array, style=wx.LB_ALWAYS_SB)

        #listboxの定義、styleはスクロールの設定
        SortListBox = wx.ListBox(panel, wx.ID_ANY,size=(400,3400),style=wx.LB_ALWAYS_SB)
        #elementArrayの代替として。日本語化
        SortListBox.Append(u"分類1","element_1")
        SortListBox.Append(u"分類2","element_2")
        SortListBox.Append(u"分類3","element_3")
        SortListBox.Append(u"分類4","element_4")
        #イベントと関連づけ
        SortListBox.Bind(wx.EVT_LISTBOX, MenuSortListBox)

        
        #配置（boxsizerで配置、カッコ内は配置していく方向）
        layout = wx.BoxSizer(wx.HORIZONTAL)
        #flagはサイズの拡大方法、｜の後ろは余白の設定（テキトー）
        layout.Add(SortListBox, flag=wx.GROW | wx.ALL, border=3)
        
        #パネルのサイズをlayoutに合わせる
        panel.SetSizer(layout)

#二つ目のリスト（物質の選択用）の定義、一つ目と一緒
class MenuIngList(wx.Frame):
    def __init__(self,sorts):
        wx.Frame.__init__(self, None,wx.ID_ANY, u"Ingredients", size=(350,350))
        panel = wx.Panel(self, wx.ID_ANY)
        panel.SetBackgroundColour("#AFAFAF")
        #global bunrui
        #ここの内容物がどう考えても変化する。引数として受け取るべきか
        #element_array = (u"forteskey",u"element_2",u"element_3")
        if sorts is not None:
            element_array = tuple(ingList)
        """多分中途半端。ここのところはIngListBoxでなければならないはず。
        if sorts=="element_1":
             SortListBox.Append(u",物質1","forteskey")
             SortListBox.Append(u",物質2","element_2")
             SortListBox.Append(u",物質3","element_3")
             SortListBox.Append(u",物質4","element_4")
             SortListBox.Append(u",物質5","element_5")
        elif sorts=="element_2":
             SortListBox.Append(u",物質1","forteskey")
             SortListBox.Append(u",物質2","element_2")
             SortListBox.Append(u",物質3","element_3")
             SortListBox.Append(u",物質4","element_4")
             SortListBox.Append(u",物質5","element_5")
        elif sorts=="element_3":
             SortListBox.Append(u",物質1","forteskey")
             SortListBox.Append(u",物質2","element_2")
             SortListBox.Append(u",物質3","element_3")
             SortListBox.Append(u",物質4","element_4")
             SortListBox.Append(u",物質5","element_5")
        elif sorts=="element_4":
             SortListBox.Append(u",物質1","forteskey")
             SortListBox.Append(u",物質2","element_2")
             SortListBox.Append(u",物質3","element_3")
             SortListBox.Append(u",物質4","element_4")
             SortListBox.Append(u",物質5","element_5")
        """
        IngListBox = wx.ListBox(panel, wx.ID_ANY, size=(350,350),choices=element_array, style=wx.LB_ALWAYS_SB)#日本語化の際はchoices=element_arrayを取り除くこと
        IngListBox.Bind(wx.EVT_LISTBOX, MenuIngListBox)
        layout = wx.BoxSizer(wx.HORIZONTAL)
        layout.Add(IngListBox, flag=wx.GROW | wx.ALL, border=3)
        panel.SetSizer(layout)
#<<<<<endDefineLists(in Menu)>>>>>


#<<<<<startDefineMainFrame/Panel>>>>>
#ボタン四つのやつのフレームの定義、root_panelに、これから定義する三つのパネルを配置する、左右のパネルはボタンの配置のみ
class CFrame(wx.Frame):
    def __init__(self):
        #フレーム定義
        wx.Frame.__init__(self, None,wx.ID_ANY, u"MainFrame", size=(795,408),)
        
        #パネル定義
        root_panel = wx.Panel(self, wx.ID_ANY)
        
        left_panel = LeftPanel(root_panel)
        center_panel = CenterPanel(root_panel)
        right_panel = RightPanel(root_panel)
        
        #配置
        root_layout = wx.BoxSizer(wx.HORIZONTAL)
        
        root_layout.Add(left_panel, 0, wx.GROW | wx.ALL)
        root_layout.Add(center_panel, 0, wx.GROW | wx.ALL)
        root_layout.Add(right_panel, 0, wx.GROW | wx.ALL)
        
        root_panel.SetSizer(root_layout)
        root_layout.Fit(root_panel)
        

class LeftPanel(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self, parent, wx.ID_ANY)
        #ボタンに関する操作(self, ID, Name, Size)
        StartButton = wx.Button(self, wx.ID_ANY, u"STAT", size=(210,203))
        MenuButton  = wx.Button(self, wx.ID_ANY, u"MENU", size=(210,203))
        #上で定義したイベントと関連付け
        StartButton.Bind(wx.EVT_BUTTON, StartClick)
        MenuButton.Bind(wx.EVT_BUTTON, MenuClick)
        
        layout = wx.BoxSizer(wx.VERTICAL)
        layout.Add(StartButton, flag=wx.GROW)
        layout.Add(MenuButton, flag=wx.GROW)
        self.SetSizer(layout)

#真ん中の画像と文字の表示部分
class CenterPanel(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self, parent,wx.ID_ANY,size=(480,400))
        global movName
        #初期画面
        if movName is None or movName==u'' or movName==u"":
            #文章を作る、styleは文字を寄せる位置
            text = wx.StaticText(self, wx.ID_ANY, u"ブロックを設定してください", style=wx.TE_CENTER)
            
            #フォントの定義と適用、サイズは最初の数字、あとは不明
            font = wx.Font(20, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
            text.SetFont(font)
            
            #配置
            layout = wx.BoxSizer(wx.VERTICAL)
            layout.Add(text, flag=wx.GROW)
            self.SetSizer(layout)
        
        #ここの下は現状ではmovNameに個別対応する形で分岐だが、それはできない。
        else:
            #画像を読み込む
            if os.path.exists("picts/"+movName+".png") is False:
                movName="NA"
            
            image = wx.Image("picts/"+movName+".png")
            
            #ここで一定の値に変更？ static
            gazou=wx.StaticBitmap(self, -1,image.ConvertToBitmap())
            
            #文章を作る
            text = wx.StaticText(self, wx.ID_ANY, movName, style=wx.TE_CENTER)
            #should be Japanese(movName  is not Japanese)
            font = wx.Font(20, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
            text.SetFont(font)
            
            #配置
            layout = wx.BoxSizer(wx.VERTICAL)
            layout.Add(text, flag=wx.GROW)
            layout.Add(gazou, flag=wx.GROW)
            self.SetSizer(layout)
        
       
class RightPanel(wx.Panel):
    def __init__(self,parent):
        wx.Panel.__init__(self, parent, wx.ID_ANY)
        ResetButton = wx.Button(self, wx.ID_ANY, u"RSET", size=(210,203))
        PowerOffButton  = wx.Button(self, wx.ID_ANY, u"Poff", size=(210,203))
        ResetButton.Bind(wx.EVT_BUTTON, ResetClick)
        PowerOffButton.Bind(wx.EVT_BUTTON, PowerOffClick)
        layout = wx.BoxSizer(wx.VERTICAL)
        layout.Add(ResetButton, flag=wx.GROW)
        layout.Add(PowerOffButton, flag=wx.GROW)
        self.SetSizer(layout)
#<<<<<endDefineMainFrame/Panel>>>>>

#<<<<<startActualMainFlow>>>>>
if __name__ == "__main__":
    MainApp = wx.App()
    ReceiveTh.start()
    global MainFrame
    MainFrame = CFrame()
    MainFrame.Center()
    MainFrame.Show()
    MainApp.MainLoop()
    GPIO.cleanup()
#<<<<<endActualMainFlow>>>>>


#<<<<<===================>>>>>
#<<<<<========EOF========>>>>>
#<<<<<===================>>>>>





