# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Ralph Eisenbach
# 
# This plugin is based on the plugin for ZoomPlayer
# by Lars-Peter Voss <bitmonster@eventghost.org>
#
# This file is a plugin for EventGhost.
# Copyright (C) 2005-2009 Lars-Peter Voss <bitmonster@eventghost.org>
#
# EventGhost is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 2 as published by the
# Free Software Foundation;
#
# EventGhost 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/>.
#

    
eg.RegisterPlugin(
    name = "TheaterTek",
    author = "SurFan",
    version = "0.0.1",
    kind = "program",
    guid = "{EF830DA5-EF08-4050-BAE0-D5FC0057D149}",
    canMultiLoad = True,
    createMacrosOnAdd = True,
    description = (
        'Adds actions to control <a href="http://www.theatertek.com/">TheaterTek</a>.'
        '\n\n<p><b>Notice:</b><br>'
        'To make it work, you have to enable TCP control in TheaterTek. '
    ),
    url = "http://www.eventghost.net/forum/viewtopic.php?t=559",
    icon = (
        "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAACGElEQVR42m1RPWhaURQ+"
        "gg6lCjooxnZIH9iARAi9QqwQTcBmioNQcWskwxV5i+AgDqHERZdsEfreUE3BDFJI4XUq"
        "EeqeizjUnw6CKO1SUJ4lWKR5PXotjaZ3eefv+873nafT6/XT6dRkMp1+PgUA0Svy9Ozs"
        "zfY2cbvdmLpcri/VOsyfDgiAxGP8SpgyxmSQFyUGQAjE2a0yWQJQoBL5i+MNWbeIcCAO"
        "qwCNaLMkPhsilFyTa9zjiXtmXQeAcg9AGEoB5mBwAChHk7TBYBAIBNLpNJYvUhfq1x/L"
        "Hti/7Yebh6VSCekbbxvomM+dn5df7b9cNY3ckWGkUqkgq9fgxUI2m81kMni0VqtVr9cP"
        "PPt3NjCghEpUUhTl5ONJ0BLsdrsIlmVZFEWn09lsNtHYHEABvoO0JlFKY7FYuVxGbi4m"
        "l8uFw+F8Pu/z+bCL4DkgBHRtxo0TuH0ymdjt9uMPxxs/N7BSLBbREpeMyxcA7bUGyw9t"
        "7Jp2G41Gv9/vdDpcVTKZ5JIIxcMCE64ESzCIw8OrYdfSxTLqsVqttVotkUiYzeZQKKQz"
        "Go3j8dhgMBwVjrZ+b/V6PVSMqd/vr1arGHAzKAan2+227vbb5K6Sd5/er68/xlMiIJVK"
        "CYJgs9kikQiy4ImeOTZXARyzs/McR1VVLRQKaGBv7wWy+J/O/sx/APjGD39dXio3NyrG"
        "o9EoGo0+efCIt/4ArUT50E11E2MAAAAASUVORK5CYII="
    ),
)

# ===================================================================
# TheaterTek TCP/IP Interface
# ===================================================================

"""\
IP COMMANDS
-----------

TT->AP		Sent from TT to client application
AP->TT		Sent from client application to TT
TT<-->AP	Sent from TT and can be polled by client.

Commands are sent ASCII in the form:
4 byte command, space, {parameter} CRLF

A successful command returns:
Command, space, 0
OR
Command, space, response

An unsuccessful command returns:
Command, space, -1

Example:
0000			// Client app
0000 TheaterTek DVD	// Returned value



Enum values
-----------
IP_MEDIASTATE	0=Stopped/NoMedia, 1=Playing, 2=paused, 3=FF, 4=RW
IP_FULLSCREEN	0=Minimized, 1=Windowed, 2=Fullscreen
IP_GETPRIVATE	Allows client to set/get a private string up to 1024 bytes on TT. This data persists as long as TT is running.


#define	IP_APPLICATION		0 	// TT<-->AP	Application name
#define	IP_VERSION		1 	// TT<-->AP	Application version
#define IP_FLASH		500 	// TT<-->AP	OSD Flash message
#define IP_FULLSCREEN		510 	// TT<-->AP	Fullscreen/windowed status

#define IP_MEDIASTATE		1000 	// TT<-->AP	State enum
#define IP_MEDIATIME		1010 	// TT<-->AP	Media time (hh:mm:ss / hh:mm:ss)
#define IP_MEDIAPOS		1020 	// AP->TT	Set media time (hh:mm:ss)
#define IP_ENDOFMEDIA		1030 	// TT->AP	Signals end of media
#define IP_FORMAT		1040	// TT->AP	(0=NTSC, 1=PAL)

#define IP_GETAR		1300 	// TT<-->AP	Return Current AR (name)
#define IP_ARCOUNT		1310 	// AP->TT	AR Count
#define IP_ARNAMES		1320 	// AP->TT	AR Names (name|name)
#define IP_SETAR		1330 	// AP->TT	Set Current AR (number)

#define IP_CURFILE		1400 	// TT<-->AP	Current file
#define	IP_DISKINSERTION	1410 	// TT->AP	Disk inserted
#define IP_DISKEJECTION		1420 	// TT->AP	Disk ejected

#define IP_DVDUNIQUEID		1500 	// AP->TT	DVD unique ID
#define IP_DVDTITLE		1510 	// TT<-->AP	Current Title
#define IP_DVDTITLECOUNT	1520 	// AP->TT	Title count
#define IP_DVDPLAYTITLE		1530 	// AP->TT	Play Title

#define IP_DVDCHAPTER		1600 	// TT<-->AP	Current Chapter
#define IP_DVDCHAPTERCOUNT	1610 	// AP->TT	Chapter count
#define IP_DVDPLAYCHAPTER	1620 	// AP->TT	Play chapter
#define IP_DVDPLAYTITCHAP	1630 	// AP->TT	Play Chapter in Title (Chapter Title)

#define IP_DVDAUDIO		1700 	// TT<-->AP	Current audio stream
#define IP_DVDSETAUDIO		1710 	// AP->TT	Set audio stream
#define IP_DVDAUDIOCOUNT	1720 	// AP->TT	Audio stream count
#define IP_DVDAUDIONAMES	1730 	// AP->TT	Audio stream names (name|name)

#define IP_DVDSUBTITLE		1800 	// TT<-->AP	Current subtitle stream
#define IP_DVDSETSUBTITLE	1810 	//	AP->TT	Set subtitle stream, -1 to disable
#define IP_DVDSUBTITLECOUNT 	1820 	// AP->TT	Subtitle stream count
#define IP_DVDSUBTITLENAMES	1830 	// AP->TT	Subtitle names (name|name)

#define IP_DVDANGLE		1900 	// TT<-->AP	Current angle
#define IP_DVDSETANGLE		1910 	// AP->TT	Set angle
#define IP_DVDANGLECOUNT	1920 	// AP->TT	Angle count

#define IP_DVDMENUMODE		2000 	// TT<-->AP	Menu mode
#define IP_DOMAIN		2010 	// TT->AP	DVD Domain

#define IP_GETVOLUME		2100 	// TT<-->AP	Get Current volume
#define IP_SETVOLUME		2110 	// AP->TT	Set Current volume
#define IP_GETAUDIOOUTPUT	2120 	// AP->TT	Get Current audio output
#define IP_SETAUDIOOUTPUT	2130 	// AP->TT	Set audio output

#define IP_ADDBOOKMARK		2200 	// AP->TT	Add a bookmark
#define IP_NEXTBOOKMARK		2210 	// AP->TT	Next bookmark
#define IP_PREVBOOKMARK		2220 	// AP->TT	Previous bookmark

#define IP_PLAYFILE		3000 	// AP->TT	Play file
#define IP_ADDFILE		3010 	// AP->TT	Add file to playlist
#define IP_CLEARLIST		3020 	// AP->TT	Clear playlist
#define IP_GETINDEX		3030 	// AP->TT	Current item index
#define IP_PLAYATINDEX		3040 	// AP->TT	Play item at index
#define IP_GETLISTCOUNT		3050 	// AP->TT	Current list count
#define IP_GETLIST		3060 	// AP->TT	Get playlist (name|name)
#define IP_DELATINDEX		3070 	// AP->TT	Delete file at index

#define IP_SETPRIVATE		4000 	// AP->TT	Private app string
#define IP_GETPRIVATE		4010 	// AP->TT	Private app string

#define IP_WM_COMMAND		5000 	// AP->TT	Internal command
#define IP_KEYPRESS		5010	// AP->TT	Key code
#define IP_SENDMSG		5020 	// AP->TT	Send message
#define IP_POSTMSG		5030 	// AP->TT	Post message


Auto Killer Commands
--------------------
#define IP_LAUNCH		8000 	// AP->AK
#define IP_QUIT			8010 	// AP->AK
#define IP_MOUNTDISK		8020 	// AP->AK	Changer#, Slot#
#define IP_UNMOUNTDISK		8030 	// AP->AK	Changer#  ->Slot#
#define IP_EJECTDISK		8040 	// AP->AK	Changer#, Slot#
#define IP_GETSLOTDATA		8050 	// AP->AK	Changer#, Slot#
#define IP_GETDRIVEDATA		8060 	// AP->AK	Changer#  ->DriveData
#define IP_CHECKCHANGED		8070 	// AP->AK		
#define IP_REBUILDDATA		8080 	// AP->AK
#define IP_DATACHANGED		8100 	// AK->AP	Notification of data change
#define IP_COUNTCHANGERS	8110 	// AP->AK



WM_COMMANDS
-----------
#define ID_PLAY                         32771
#define ID_STOP                         32772
#define ID_PAUSE                        32773
#define ID_NEXT                         32774
#define ID_PREVIOUS                     32775
#define ID_EXIT                         32776
#define ID_FF                           32777
#define ID_RW                           32778
#define ID_MENU_LIST                    32779
#define ID_TITLE_MENU                   32780
#define ID_FF_1X                        32782
#define ID_FF_2X                        32784
#define ID_FF_5X                        32785
#define ID_FF_10X                       32786
#define ID_FF_20X                       32787
#define ID_FF_SLOW                      32788
#define ID_RW_1X                        32790
#define ID_RW_2X                        32791
#define ID_RW_5X                        32792
#define ID_RW_10X                       32793
#define ID_RW_20X                       32794
#define ID_ROOT_MENU                    32796
#define ID_AUDIO_MENU                   32797
#define ID_SUBTITLE_MENU                32798
#define ID_CHAPTER_MENU                 32799
#define ID_CC_ON                        32804
#define ID_CC_OFF                       32805
#define ID_ABOUT                        32807
#define ID_SUB_OFF                      32808
#define ID_ASPECT_DEFINE                32810
#define ID_ASPECT_ANAM                  32811
#define ID_ASPECT_NONANAM               32812
#define ID_ASPECT_LETTERBOX             32813
#define ID_BOOK_ADD                     32814
#define ID_BUTTON32819                  32819
#define ID_BUTTON32820                  32820
#define ID_ONSCREEN                     32821
#define ID_VID_BRIGHTNESS               32824
#define ID_VID_CONTRAST                 32825
#define ID_VID_HUE                      32826
#define ID_VID_SATURATION               32827
#define ID_OVERSCAN                     32828
#define ID_VID_GAMMA                    32829
#define ID_MENU_CHAPTER                 32830
#define ID_MENU_AUDIO                   32831
#define ID_MENU_ANGLE                   32832
#define ID_MENU_FF                      32833
#define ID_MENU_SUBTITLES               32834
#define ID_CLOSED_CAPTIONS              32835
#define ID_BOOK_DELETE                  32836
#define ID_ANGLE_MENU                   32837
#define ID_RESUME                       32838
#define ID_MENU_TITLE                   32839
#define ID_SETUP                        32841
#define ID_ADJUSTVIDEO                  32842
#define ID_ASPECT_LOCK                  32843
#define ID_SETSTARTPOINT                32846
#define ID_K_RETURN                     32849
#define ID_K_UP                         32850
#define ID_K_DOWN                       32851
#define ID_K_LEFT                       32852
#define ID_K_RIGHT                      32853
#define ID_K_FF                         32854
#define ID_K_RW                         32855
#define ID_K_ESCAPE                     32856
#define ID_NEXTAR                       32857
#define ID_INFO                         32858
#define ID_ARFIRST                      32859
#define ID_AR2                          32860
#define ID_AR3                          32861
#define ID_AR4                          32862
#define ID_AR5                          32863
#define ID_AR6                          32864
#define ID_AR7                          32865
#define ID_AR8                          32866
#define ID_AR9                          32867
#define ID_ARLAST                       32868
#define ID_EJECT                        32870
#define ID_CONTEXT                      32872
#define ID_ALTEXIT                      32873
#define ID_MINIMIZE                     32874
#define ID_NEXTSUB                      32875
#define ID_NEXTAUDIO                    32876
#define ID_REPLAY                       32877
#define ID_JUMP                         32878
#define ID_FRAMESTEP                    32879
#define ID_ABREPEAT                     32880
#define ID_CHAPTITREP                   32881
#define ID_NEXT_ANGLE                   32883
#define ID_OPEN                         32884
#define ID_NEXT_TIT                     32885
#define ID_STATS                        32886
#define ID_CAPTURE                      32887
#define ID_BK_RESUME                    32888
#define ID_DEINTERLACE                  32889
#define ID_VOLUP                        32891
#define ID_VOLDOWN                      32892
#define ID_NEXTDISK                     32893
#define ID_SHOWTIME                     32894
#define ID_CC_NUDGE_UP                  32895
#define ID_CC_NUDGE_DOWN                32896
#define ID_UPGRADE                      32897
#define ID_NEXT_FILE                    32898
#define ID_PREVIOUS_FILE                32899
#define ID_TSPROG                       32901
#define ID_PREV_TIT                     32902
#define ID_SLOW                         32904
#define ID_CCTOGGLE                     32905
#define ID_AR11                         32906
#define ID_AR12                         32907
#define ID_AR13                         32908
#define ID_AR14                         32909
#define ID_AR15                         32910
#define ID_AR16                         32911
#define ID_AR17                         32912
#define ID_AR18                         32913
#define ID_AR19                         32914
#define ID_AR20                         32915
#define ID_VMRSTATS                     32916
#define ID_LIPDOWN                      32917
#define ID_LIPUP                        32918
#define ID_MUTE                         32919
#define ID_BLANKING                     32920
#define ID_TOGGLE                       32922
#define ID_MOVELEFT                     32924
#define ID_MOVERIGHT                    32925
#define ID_MOVEUP                       32926
#define ID_MOVEDOWN                     32927
#define ID_H_EXPAND                     32928
#define ID_H_CONTRACT                   32929
#define ID_V_EXPAND                     32930
#define ID_V_CONTRACT                   32931
#define ID_ZOOM_IN                      32932
#define ID_ZOOM_OUT                     32933
#define ID_BL_LEFT                      32934
#define ID_BL_RIGHT                     32935
#define ID_BT_UP                        32936
#define ID_BT_DOWN                      32937
#define ID_BR_LEFT                      32938
#define ID_BR_RIGHT                     32939
#define ID_BB_UP                        32940
#define ID_BB_DOWN                      32941
#define ID_STREAM                       32943

"""

import asynchat
import socket
import asyncore
import threading
import new

ttRequests = (
('IP_APPLICATION', '0000', 'Request Application name'),
('IP_VERSION', '0001', 'Request Application version'),
('IP_FULLSCREEN', '0510', 'Request Fullscreen/windowed status'),
('IP_MEDIASTATE', '1000', 'Request MediaState'),
('IP_MEDIATIME', '1010', 'Request Media time'),
('IP_ENDOFMEDIA', '1030', 'End of media'),
('IP_FORMAT', '1040', 'Request Video Format'),
('IP_GETAR', '1300', 'Request Current Aspect Ratio'),
('IP_ARCOUNT', '1310', 'Request Aspect Ratio Count'),
('IP_ARNAMES', '1320', 'ARequest Aspect Ratio Names'),
('IP_CURFILE', '1400', 'Request Current file'),
('IP_DISKINSERTION', '1410', 'Disk inserted'),
('IP_DISKEJECTION', '1420', 'Disk ejected'),
('IP_DVDUNIQUEID', '1500', 'DVD unique ID'),
('IP_DVDTITLE', '1510', 'Request Current Title'),
('IP_DVDTITLECOUNT', '1520', 'Request Title count'),
('IP_DVDCHAPTER', '1600', 'Request Current Chapter'),
('IP_DVDCHAPTERCOUNT', '1610', 'Request Chapter count'),
('IP_DVDAUDIO', '1700', 'Request Current audio stream'),
('IP_DVDAUDIOCOUNT', '1720', 'Request Audio stream count'),
('IP_DVDAUDIONAMES', '1730', 'Request Audio stream names'),
('IP_DVDSUBTITLE', '1800', 'Request Current subtitle stream'),
('IP_DVDSUBTITLECOUNT', '1820', 'Request Subtitle stream count'),
('IP_DVDSUBTITLENAMES', '1830', 'Request Subtitle names (name|name)'),
('IP_DVDANGLE', '1900', 'Request Current angle'),
('IP_DVDANGLECOUNT', '1920', 'Request Angle count'),
('IP_DVDMENUMODE', '2000', 'Request Menu mode'),
('IP_DOMAIN', '2010', 'Request DVD Domain'),
('IP_GETVOLUME', '2100', 'Request Current volume'),
('IP_GETAUDIOOUTPUT', '2120', 'Request Current audio output'),
('IP_GETLISTCOUNT', '3050', 'Request Current list count'),
('IP_GETLIST', '3060', 'Request  playlist'),
('IP_GETPRIVATE', '4010', 'Request Private app string'),
('IP_COUNTCHANGERS', '8110', 'CountChangers'), 
)

ttCommands = (
('IP_FLASH', '0500', 'OSD Flash message','Message'),
('IP_MEDIAPOS', '1020', 'Set media time', 'Time(hh:mm:ss)'),
('IP_SETAR', '1330', 'Set Current AR', 'AR number'),
('IP_DVDPLAYTITLE', '1530', 'Play Title', 'Title Number'),
('IP_DVDPLAYCHAPTER', '1620', 'Play chapter', 'Chapter number'),
('IP_DVDPLAYTITCHAP', '1630', 'Play Chapter in Title', 'Title/Chapter (space delimited)'),
('IP_DVDSETAUDIO', '1710', 'Set audio stream','Stream number'),
('IP_DVDSETSUBTITLE', '1810', 'Set subtitle stream', 'Stream number (-1 to disable)'),
('IP_DVDSETANGLE', '1910', 'Set angle', 'Angle'),
('IP_SETVOLUME', '2110', 'Set Current volume', 'Volume'),
('IP_SETAUDIOOUTPUT', '2130', 'Set audio output', 'Audio Output'),
('IP_ADDBOOKMARK', '2200', 'Add a bookmark', ''),
('IP_NEXTBOOKMARK', '2210', 'Next bookmark', ''),
('IP_PREVBOOKMARK', '2220', 'Previous bookmark', ''),
('IP_PLAYFILE', '3000', 'Play file', 'Filename'),
('IP_ADDFILE', '3010', 'Add file to playlist', 'Filename'),
('IP_CLEARLIST', '3020', 'Clear playlist', ''),
('IP_PLAYATINDEX', '3040', 'Play item at index', 'Index'),
('IP_GETINDEX', '3030', 'Current item index', 'Index'),
('IP_DELATINDEX', '3070', 'Delete file at index', 'Index'),
('IP_SETPRIVATE', '4000', 'Private app string', 'String'),
('IP_KEYPRESS', '5010', 'Key code', 'Key-Code'),
('ID_PLAY', '32771', 'Play', ''),
('ID_STOP', '32772', 'Stop', ''),
('ID_PAUSE', '32773', 'Pause', ''),
('ID_NEXT', '32774', 'Next', ''),
('ID_PREVIOUS', '32775', 'Previous', ''),
('ID_EXIT', '32776', 'Exit', ''),
('ID_FF', '32777', 'FastForward', ''),
('ID_RW', '32778', 'Fast Rewind', ''),
('ID_MENU_LIST', '32779', 'Menu List', ''),
('ID_TITLE_MENU', '32780', 'Title Menu', ''),
('ID_FF_1X', '32782', 'Normal Play', ''),
('ID_FF_2X', '32784', 'Fast Forward 2x', ''),
('ID_FF_5X', '32785', 'Fast Forward 5x', ''),
('ID_FF_10X', '32786', 'Fast Forward 10x', ''),
('ID_FF_20X', '32787', 'Fast Forward 20x', ''),
('ID_FF_SLOW', '32788', 'Fast Forward Slow', ''),
('ID_RW_1X', '32790', 'Reverse Play', ''),
('ID_RW_2X', '32791', 'Fast Reverse 2X', ''),
('ID_RW_5X', '32792', 'Faste Reverse 5X', ''),
('ID_RW_10X', '32793', 'Fast Reverse 10X', ''),
('ID_RW_20X', '32794', 'Fast Reverse 20X', ''),
('ID_ROOT_MENU', '32796', 'Root Menu', ''),
('ID_AUDIO_MENU', '32797', 'Audio Menu', ''),
('ID_SUBTITLE_MENU', '32798', 'Subtitle Menu', ''),
('ID_CHAPTER_MENU', '32799', 'Chapter Menu', ''),
('ID_CC_ON', '32804', 'Closed Captions On', ''),
('ID_CC_OFF', '32805', 'Closed Captions Off', ''),
('ID_ABOUT', '32807', 'About', ''),
('ID_SUB_OFF', '32808', 'Subtitles Off', ''),
('ID_ASPECT_DEFINE', '32810', 'Define Aspect Ratio', ''),
('ID_ASPECT_ANAM', '32811', 'AR anamorph', ''),
('ID_ASPECT_NONANAM', '32812', 'AR non anamorph', ''),
('ID_ASPECT_LETTERBOX', '32813', 'AR Letterbox', ''),
('ID_BOOK_ADD', '32814', 'Add Bookmark', ''),
('ID_BUTTON32819', '32819', 'BUTTON32819', ''),
('ID_BUTTON32820', '32820', 'BUTTON32820', ''),
('ID_ONSCREEN', '32821', 'On Screen', ''),
('ID_VID_BRIGHTNESS', '32824', 'Brightness', ''),
('ID_VID_CONTRAST', '32825', 'Contrast', ''),
('ID_VID_HUE', '32826', 'Hue', ''),
('ID_VID_SATURATION', '32827', 'Saturation', ''),
('ID_OVERSCAN', '32828', 'Overscan', ''),
('ID_VID_GAMMA', '32829', 'Gamma', ''),
('ID_MENU_CHAPTER', '32830', 'Menu Chapter', ''),
('ID_MENU_AUDIO', '32831', 'Menu Audio', ''),
('ID_MENU_ANGLE', '32832', 'Menu Angle', ''),
('ID_MENU_FF', '32833', 'Menu FF', ''),
('ID_MENU_SUBTITLES', '32834', 'Menu Subtitles', ''),
('ID_CLOSED_CAPTIONS', '32835', 'Closed Captions', ''),
('ID_BOOK_DELETE', '32836', 'Delete Bookmark', ''),
('ID_ANGLE_MENU', '32837', 'Angle Menu', ''),
('ID_RESUME', '32838', 'Resume', ''),
('ID_MENU_TITLE', '32839', 'Menu Title', ''),
('ID_SETUP', '32841', 'Setup', ''),
('ID_ADJUSTVIDEO', '32842', 'Adjust Video', ''),
('ID_ASPECT_LOCK', '32843', 'Lock Aspect ratio', ''),
('ID_SETSTARTPOINT', '32846', 'Set Startpoint', ''),
('ID_K_RETURN', '32849', 'Key Return', ''),
('ID_K_UP', '32850', 'Key Up', ''),
('ID_K_DOWN', '32851', 'Key Down', ''),
('ID_K_LEFT', '32852', 'Key Left', ''),
('ID_K_RIGHT', '32853', 'Key Right', ''),
('ID_K_FF', '32854', 'Key FastForward', ''),
('ID_K_RW', '32855', 'Key Rewind', ''),
('ID_K_ESCAPE', '32856', 'Key Escape', ''),
('ID_NEXTAR', '32857', 'Next Aspect ratio', ''),
('ID_INFO', '32858', 'Info', ''),
('ID_ARFIRST', '32859', 'First Aspect Ratio', ''),
('ID_AR2', '32860', 'Aspect ratio 2', ''),
('ID_AR3', '32861', 'Aspect ratio 3', ''),
('ID_AR4', '32862', 'Aspect ratio 4', ''),
('ID_AR5', '32863', 'Aspect ratio 5', ''),
('ID_AR6', '32864', 'Aspect ratio 6', ''),
('ID_AR7', '32865', 'Aspect ratio 7', ''),
('ID_AR8', '32866', 'Aspect ratio 8', ''),
('ID_AR9', '32867', 'Aspect ratio 9', ''),
('ID_ARLAST', '32868', 'Last Aspect ratio', ''),
('ID_EJECT', '32870', 'Eject', ''),
('ID_CONTEXT', '32872', 'Context', ''),
('ID_ALTEXIT', '32873', 'ALT Exit', ''),
('ID_MINIMIZE', '32874', 'Minimize', ''),
('ID_NEXTSUB', '32875', 'Next Subtitle', ''),
('ID_NEXTAUDIO', '32876', 'Next Audio', ''),
('ID_REPLAY', '32877', 'Replay', ''),
('ID_JUMP', '32878', 'Jump', ''),
('ID_FRAMESTEP', '32879', 'Framestep', ''),
('ID_ABREPEAT', '32880', 'A/B-Repeat', ''),
('ID_CHAPTITREP', '32881', 'Chapter Title Repeat', ''),
('ID_NEXT_ANGLE', '32883', 'Next Angle', ''),
('ID_OPEN', '32884', 'Open', ''),
('ID_NEXT_TIT', '32885', 'Next Title', ''),
('ID_STATS', '32886', 'Statistics', ''),
('ID_CAPTURE', '32887', 'Capture', ''),
('ID_BK_RESUME', '32888', 'BK Resume', ''),
('ID_DEINTERLACE', '32889', 'Deinterlace', ''),
('ID_VOLUP', '32891', 'Volume Up', ''),
('ID_VOLDOWN', '32892', 'Volume Down', ''),
('ID_NEXTDISK', '32893', 'Next Disk', ''),
('ID_SHOWTIME', '32894', 'Show Time', ''),
('ID_CC_NUDGE_UP', '32895', 'CC Nudge Up', ''),
('ID_CC_NUDGE_DOWN', '32896', 'CC Nudge Down', ''),
('ID_UPGRADE', '32897', 'Upgrade', ''),
('ID_NEXT_FILE', '32898', 'Next File', ''),
('ID_PREVIOUS_FILE', '32899', 'Previous File', ''),
('ID_TSPROG', '32901', 'TSPROG', ''),
('ID_PREV_TIT', '32902', 'Previous Title', ''),
('ID_SLOW', '32904', 'Slow', ''),
('ID_CCTOGGLE', '32905', 'Closed Captions Toggle', ''),
('ID_AR11', '32906', 'Aspect ratio 11', ''),
('ID_AR12', '32907', 'Aspect ratio 12', ''),
('ID_AR13', '32908', 'Aspect ratio 13', ''),
('ID_AR14', '32909', 'Aspect ratio 14', ''),
('ID_AR15', '32910', 'Aspect ratio 15', ''),
('ID_AR16', '32911', 'Aspect ratio 16', ''),
('ID_AR17', '32912', 'Aspect ratio 17', ''),
('ID_AR18', '32913', 'Aspect ratio 18', ''),
('ID_AR19', '32914', 'Aspect ratio 19', ''),
('ID_AR20', '32915', 'Aspect ratio 20', ''),
('ID_VMRSTATS', '32916', 'VMR Statistics', ''),
('ID_LIPDOWN', '32917', 'Lipsync down', ''),
('ID_LIPUP', '32918', 'Lipsync Up', ''),
('ID_MUTE', '32919', 'Mute', ''),
('ID_BLANKING', '32920', 'Blanking', ''),
('ID_TOGGLE', '32922', 'Toggle', ''),
('ID_MOVELEFT', '32924', 'Move Left', ''),
('ID_MOVERIGHT', '32925', 'Move Right', ''),
('ID_MOVEUP', '32926', 'Move Up', ''),
('ID_MOVEDOWN', '32927', 'Move Down', ''),
('ID_H_EXPAND', '32928', 'Horizontal Expand', ''),
('ID_H_CONTRACT', '32929', 'Horizontal Contract', ''),
('ID_V_EXPAND', '32930', 'Vertical Expand', ''),
('ID_V_CONTRACT', '32931', 'Vertical Contract', ''),
('ID_ZOOM_IN', '32932', 'Zoom In', ''),
('ID_ZOOM_OUT', '32933', 'Zoom Out', ''),
('ID_BL_LEFT', '32934', 'BL_LEFT', ''),
('ID_BL_RIGHT', '32935', 'BL_RIGHT', ''),
('ID_BT_UP', '32936', 'BT_UP', ''),
('ID_BT_DOWN', '32937', 'BT_DOWN', ''),
('ID_BR_LEFT', '32938', 'BR_LEFT', ''),
('ID_BR_RIGHT', '32939', 'BR_RIGHT', ''),
('ID_BB_UP', '32940', 'BB_UP', ''),
('ID_BB_DOWN', '32941', 'BB_DOWN', ''),
('ID_STREAM', 32943, 'STREAM', ''),
)

ttAutoKillerAndChangerCommands = (
('IP_LAUNCH', '8000', 'Launch AutoKiller'), 
('IP_QUIT', '8010', 'Quit Autokiller'),
('IP_MOUNTDISK', '8020', 'Mount Disk', 'Changer/Slot (comma delimited)'),
('IP_UNMOUNTDISK', '8030', 'Unmount Disk', 'Changer/Slot (comma delimited)'),
('IP_EJECTDISK', '8040', 'Eject Disk', 'Changer/Slot (comma delimited)'),
('IP_GETSLOTDATA', '8050', 'GETSLOTDATA', 'Changer, Slot'),
('IP_GETDRIVEDATA', '8060', 'GETDRIVEDATA', 'Changer  ->DriveData'),
('IP_CHECKCHANGED', '8070', 'CHECKCHANGED'),
('IP_REBUILDDATA',  '8080',  'REBUILDDATA'),
('IP_DATACHANGED', '8100', 'Notification of data change'),
) 

class TheaterTekSession(asynchat.async_chat):
    """
    Handles a Theatertek TCP/IP session.
    """
    
    def __init__ (self, plugin, address):
        self.plugin = plugin

        # Call constructor of the parent class
        asynchat.async_chat.__init__(self)

        # Set up input line terminator
        self.set_terminator('\r\n')

        # Initialize input data buffer
        self.buffer = ''
        
        # create and connect a socket
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        eg.RestartAsyncore()
        self.settimeout(1.0)
        try:
            self.connect(address)
        except:
            pass

    def handle_connect(self):
        """
        Called when the active opener's socket actually makes a connection. 
        """
        self.plugin.TriggerEvent("Connected")
         
       
    def handle_expt(self):
        # connection failed
        self.plugin.isSessionRunning = False
        self.plugin.TriggerEvent("NoConnection")
        self.close()


    def handle_close(self):
        """
        Called when the channel is closed.
        """
        self.plugin.isSessionRunning = False
        self.plugin.TriggerEvent("ConnectionLost")
        self.close()


    def collect_incoming_data(self, data):
        """
        Called with data holding an arbitrary amount of received data.
        """
        self.buffer = self.buffer + data


    def found_terminator(self):
        """
        Called when the incoming data stream matches the termination 
        condition set by set_terminator.
        """
        # call the plugins handler method
        self.plugin.ValueUpdate(self.buffer)
        
        # reset the buffer
        self.buffer = ''
         
class stdAction(eg.ActionClass):
    
    def __call__(self):
        self.plugin.DoCommand(self.value)
         
class stdActionWithStringParameter(eg.ActionWithStringParameter):
    
    def __call__(self, Param):
        self.plugin.DoCommand(self.value + " " + Param)
         
class wmAction(eg.ActionClass):
    
    def __call__(self):
        self.plugin.DoCommand("5000 " + self.value)
      
class TheaterTek(eg.PluginClass):
   
    def __init__(self):
        self.host = "localhost"
        self.port = 2663
        self.isSessionRunning = False
        self.timeline = ""
        self.waitStr = None
        self.waitFlag = threading.Event()
        self.PlayState = -1
        self.lastMessage = {}
        self.lastSubtitleNum = 0
        self.lastSubtitlesEnabled = False
        self.lastAudioTrackNum = 0
       
        group = self.AddGroup('Requests')
        for className, scancode, descr in ttRequests:
            clsAttributes = dict(name=descr, value=scancode)
            cls = new.classobj(className, (stdAction,), clsAttributes)
            group.AddAction(cls)
       
        group = self.AddGroup('Commands')
        for className, scancode, descr, ParamDescr in ttCommands:
            clsAttributes = dict(name=descr, value=scancode)
            if ParamDescr == "":
                 if className[0:3] == "IP_":
                    cls = new.classobj(className, (stdAction,), clsAttributes)
                 else:
                    cls = new.classobj(className, (wmAction,), clsAttributes)
            else:
                cls = new.classobj(className, (stdActionWithStringParameter,), clsAttributes)
                cls.parameterDescription = ParamDescr
            group.AddAction(cls)

    def __start__(
        self,
        host="localhost", 
        port=2663,
        dummy1=None,
        dummy2=None,
        useNewEvents=False
    ):
        self.host = host
        self.port = port
        self.events = self.ttEvents
        
    ttEvents = {
        "0000": "ApplicationName",
        "0001": "Version",
        "0500": "OSD",
        "0510": (
            "WindowState",
            {
                "0": "Minimized",
                "1": "Windowed",
                "2": "Fullscreen"
            },
        ),
        "1000": (
            "MediaState",
            {
                "0": "Stopped",
                "1": "Playing",
                "2": "Paused",
                "3": "FF",
                "4": "RW"
            },
        ),
        "1010": "MediaTime",
        "1030": "EndOfMedia",
        "1040": (
            "Format",
            {
                "0": "NTSC",
                "1": "PAL",
            },
        ),
        "1300": "AspectRatio",
        "1310": "AspectRatioCount",
        "1320": "AspectRatioNames",
        "1400": "Currentfile",
        "1410": "DiskInserted",
        "1420": "DiskEjected",
        "1500": "DVDUniqueID",
        "1510": "CurrentTitle",
        "1520": "TitleCount",
        "1600": "CurrentChapter",
        "1610": "ChapterCount",
        "1700": "CurrentAudioStream",
        "1720": "AudioStreamCount",
        "1730": "AudioStreamNames",
        "1800": "CurrentSubtitleStream",
        "1820": "SubtitleStreamCount",
        "1830": "SubtitleNames",
        "1900": "CurrentAngle",
        "1920": "AngleCount",
        "2000": (
            "MenuMode",
            {
                "0": "Off",
                "1": "On",
            },
        ),
        "2010": "DVDDomain",
        "2100": "CurrentVolume",
        "2120": "CurrentAudioOutput",
        "3050": "CurrentListCount",
        "3060": "Playlist",
        "4010": "PrivateAppString",
        "8110": "CountChangers",
    }
    
    def ValueUpdate(self, text):
        if text == self.waitStr:
            self.waitStr = None
            self.waitFlag.set()
            return
        header = text[0:4]
        state = text[5:].decode('utf-8')
        self.lastMessage[header] = state
        ttEvent = self.ttEvents.get(header, None)
        if ttEvent is not None:
            if type(ttEvent) == type({}):
                eventString = ttEvent.get(state, None)
                if eventString is not None:
                    self.TriggerEvent(eventString)
                else:
                    self.TriggerEvent(header, [state])
            elif type(ttEvent) == type(()):
                suffix2 = ttEvent[1].get(state, None)
                if suffix2 is not None:
                    self.TriggerEvent(ttEvent[0] + "." + suffix2)
                else:
                    self.TriggerEvent(ttEvent[0] + "." + str(state))
            else:
                if state == "":
                    self.TriggerEvent(ttEvent)
                else:
                    self.TriggerEvent(ttEvent, [state])
            return
        else:
            self.TriggerEvent(header, [state])

    @eg.LogIt
    def DoCommand(self, cmdstr):
        self.waitFlag.clear()
        self.waitStr = cmdstr
        if not self.isSessionRunning:
            self.session = TheaterTekSession(self, (self.host, self.port))
            self.isSessionRunning = True
        try:
            self.session.sendall(cmdstr + "\r\n")
        except:
            self.isSessionRunning = False
            self.TriggerEvent('close')
            self.session.close()
        self.waitFlag.wait(1.0)
        self.waitStr = None
        self.waitFlag.set()


    def SetOSD(self, text):
        self.DoCommand("1200 " + text)


    def Configure(
        self,
        host="localhost",
        port=2663,
        dummy1=None,
        dummy2=None
    ):
        panel = eg.ConfigPanel(self)
        hostEdit = panel.TextCtrl(host)       
        portEdit = panel.SpinIntCtrl(port, max=65535)
        panel.AddLine("TCP/IP host:", hostEdit)
        panel.AddLine("TCP/IP port:", portEdit)
        while panel.Affirmed():
            panel.SetResult(
                hostEdit.GetValue(), 
                portEdit.GetValue(), 
                None,
                None
            )
    
    class MyCommand(eg.ActionWithStringParameter):
        name = "Raw Command"
        
        def __call__(self, cmd):
            self.plugin.DoCommand(cmd)
