#!/bin/env python

###########################################################################
# Modified ced2go script by Thorben Quast, 28/07/2015
# allowing easier access to the more detailled detector drawing of CLIC/ILD
# without GEAR. Modified/added sections are labeled.
# 
# Usage:
# - "ced2go -d <rel. path of detectorFile.xml> <rel. path of slcioFile>" 
#    triggers the new implemented drawing. CLIC and ILD geometry are 
#    distinguished by the info tag's name attribute in the geometry file
# - "ced2go" -d <rel. path of gearFile.xml> <rel. path of slcioFile>
#    a gear file is assumed to be given and the drawing is performed 
#    as usual.
# 
###########################################################################

import sys
import re
if sys.version_info[0] > 2 or ( sys.version_info[0] == 2 and sys.version_info[1]>= 4):
    import subprocess
    old = 0
else:
    print "Warning: Python Version < 2.4..."
    old = 1
    import popen2
import os
import signal
import time
import getopt

import socket
import sys

import random

''' Start of addition by T. Quast '''
from xml.dom import minidom 
sys_path_to_ced2go_template = os.path.abspath(sys.path[0])
userDefinedXML = False
''' End of addition by T. Quast '''

#default steering file template: Gear dependent
templateXMLFile = os.path.join( sys_path_to_ced2go_template, "ced2go-template.xml" )

#Help output
def help():
    print "\n-------------- Help -------------"
    print "Usage: " + str(sys.argv[0]) + " [OPTION]  <LCIO Input File>"
    print "Options: "
    print "     -v            Viewer1"
    print "     -v            Viewer2"
    print "     -d            Detector description as LCDD or Gear"
    print "     -h/-?         Help"
    print "     -t            template file ["+templateXMLFile+"]"
    print "     -s            arg = 1 enables preferred drawing of surfaces (if available); works only with LCDD"
    print "     --MarlinParameter=value            overwrites existing parameters in the steering file"
    print "All options are optional"
    print "Viewers are e.g. CEDViewer, DSTViewer, GenericViewer"
    print "---------------------------------"
#import shlex
#from Tkinter import *
#import threading

#The global variables, paths and commands
viewer   = "CEDViewer" #default viewer

if not os.path.isfile(templateXMLFile):
    print "Error: Template File \"" + templateXMLFile + "\" not found!"
    sys.exit()


#extractDetector = os.path.join( os.path.abspath(sys.path[0]), "extractdetector" )
extractDetector = "extractdetector"  #extractdetector.cc is located in the same directory as ced2go


#if not os.path.isfile(extractDetector):
#    print "Error: Helper Tool \"" + extractDetector + "\" not found!"
#    sys.exit()

steeringFile="/tmp/ced2go_" + os.environ['USER'] + "_steering.xml"
CED= "glced"
Marlin="Marlin"

keys = {'$LCIOInputFiles$':'', 
        '$GearXMLFile$':'',
        '$Viewer$':'',
        '$DD4XMLFile$':'',
        '$DrawSurfaces$': 'false'
       }
#Parse the command line arguments
commandline = sys.argv[1:]     #is a list
#parse for Marlin commands that star with '--'
marlincommands= []
for entry in reversed(commandline):
    if entry.startswith("--"):
        marlincommands.append(entry)
        commandline.remove(entry)
try: 
    opts, args = getopt.getopt(commandline, "h:v:d:t:s:", "help")
except getopt.GetoptError, err:
    print str(err)
    help()
    sys.exit(2)

detector = ""
for key in opts:
    if key[0] == "-d":
        detector=key[1]
        if not os.path.isfile(detector):
            print "Error: Gearfile \"" + detector + "\" not found!"
            sys.exit()
    if key[0] == "-t":
        templateXMLFile=key[1]
        userDefinedXML = True
        if not os.path.isfile(templateXMLFile):
            print "Error: template \"" + templateXMLFile + "\" not found!"
            sys.exit()
    if key[0]  == "-v":
          keys['$Viewer$'] += "\n<processor name=\"My" + str(key[1]) + "\"/>"
    if key[0]  == "-s":
        keys['$DrawSurfaces$'] = 'true' if (key[1] == "1") else 'false'
    if key[0] in ("-h", "--help"):
        help()
        sys.exit(0)

if keys['$Viewer$'] == '': #default
    keys['$Viewer$'] = "<processor name=\"My" + viewer + "\"/>" 


#class Thread1(threading.Thread):
#    def run(self):
#        print "thread 1 startet and block"
#        while True:
#            pass

#Thread1().start()
#print "main sleep 5sec"
#time.sleep(5)
#sys.exit()

#check if lcio file is given
if not len(args) == 1:
    help()
    sys.exit()
#check if lcio file exists
if not os.path.isfile(args[0]):
    print "Error: LCIO File \"" + args[0] + "\" not found!"
    help()
    sys.exit()
    
keys['$LCIOInputFiles$']=os.path.abspath(args[0])   #this allows for relative path inputs by the user

if detector != "": #user defined gearfile
    ''' Start of addition by T. Quast '''
    xmlDetectorFile = minidom.parse(detector)
    if len(xmlDetectorFile.getElementsByTagName('lccdd')) > 0:
        keys['$DD4XMLFile$'] = detector
        #use different steering file template
        if not userDefinedXML:
            templateXMLFile = os.path.join( sys_path_to_ced2go_template, "ced2go-template-DD4.xml" )
    else:
        keys['$GearXMLFile$'] = detector

else:  #find out the detector name used in the lcio file

    try:
        standartconfig=os.environ["STANDARDCONFIG"]
    except: 
        print "Error: $STANDARDCONFIG not set. Either use option -d to point to your gearfile or set STANDARDCONFIG appropriately"
        sys.exit(1)

    gearfiles={'ILD_00':standartconfig + '/mc2008/gear_ILD_00.xml',
            'LDC01_06Sc':standartconfig+ '/mc2008/gear_LDC01_06Sc.xml',
            'LDCPrime_02Sc':standartconfig+'/mc2008/gear_LDCPrime_02Sc.xml',
            'LDC_GLD_01Sc':standartconfig+ '/mc2008/gear_LDC_GLD_01Sc.xml'
    }

    if old:
        detector=os.popen(extractDetector + " " + keys['$LCIOInputFiles$']).readline()
    else:
        detector= str(subprocess.Popen([extractDetector,keys['$LCIOInputFiles$']], stdout=subprocess.PIPE).communicate()[0])

    detector=detector.rstrip() #remove newline

    print '"' + detector + '"'

    tmp = detector.split("\n")
    if len(tmp) != 1:
        print "Warning: LCIO File contains more than one detector model, try the first one"
        detector=tmp[0]
    try: 
        keys['$GearXMLFile$'] = gearfiles[detector] 
    except(KeyError):
        print "Error: Unknown detector in LCIO file - provide correct gear file on command line with option -d"
        sys.exit(1)


#replace the words from dict with the keywords in the template file
templateFH = open(templateXMLFile,'r')
xmlFH = open(steeringFile,'w')

for line in templateFH:
    for key in keys: 
        line= re.sub(re.escape(key),keys[key],line);
    xmlFH.write(line) 
xmlFH.close()
templateFH.close()

#check for a free port for CED 
for port in range(int(random.random()*6000+1024),200000):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(('',port))
    except socket.error, (value,message):
        if value == 98: #port already in use
            #print "port " + str(port) + " in use "
            s.close() 
            continue 
        else:
            print "unknown error: " + message
            sys.exit()
    print "Use port " + str(port)
    s.close()
    break
os.environ['CED_PORT']=str(port)

#start ced and marlin
if old:
    os.system(CED + " -geometry "+ "800x600" + " & sleep 1; " + Marlin  + " " + steeringFile);
else:
    CEDobj    = subprocess.Popen([CED,'-geometry', '800x600'])
    
    MarlinCallArgs = [Marlin, steeringFile]
    for marlinOpt in marlincommands:
        MarlinCallArgs.append(marlinOpt)
    Marlinobj = subprocess.Popen(MarlinCallArgs)

    #terminate the both processes when one is closed
    while True: 
        if Marlinobj.poll() != None:
            os.kill(CEDobj.pid,15)
            break

        if CEDobj.poll() != None: 
            os.kill(Marlinobj.pid,15)
            break

        time.sleep(0.5) #sleep for 0.5 seconds

print "Done"
