#place this file in Temp Outputs and double-click to run it
#if placed somewhere else, update prefix

import glob
import re

#GET TRACESTATE OBJECT NAMES
traceObjects = ['BPBerth1','BPBerth2']

#STATES THAT EXIST FOR OCCUPIED
states = ['Wait to Handle','Handling delay - RampUp','Handling','Handling delay - RampDown','Wait for Conditions to Clear Berth','Handling delay - Weather','Pre-Handling Time','Post-Handling Time']

#GET RUN NAMES
runFiles = glob.glob('*.rep')
runFiles = ['BP-185-20.rep']

flag = True #change to true to output intermediate files

#prefix = '../../02 - Temp Outputs' #py file is located in run files.
prefix = './' #py file is located in temp outputs

#End time is not the same as the end of simulation time because of initialization. This is user-defined.
initialization = 1
simYears = 50   #does not include initialization
hoursPerYear = 8760.0

initHours = initialization*hoursPerYear
simEndTime = hoursPerYear*simYears

def main(flag):
    endTimeIndex = 3
    startTimeIndex = 0
    berthNameIndex = 1
    durationIndex = 2
    for run in runFiles:
        print run
        overlapOccupied = 0.0
        Dict3 = []
        data = [[],[]]
        for i in range(len(traceObjects)):
            with open(prefix+run[:-4]+'-'+traceObjects[i]+'.trc') as fread:
                alllines = []
                alllines = fread.readlines()
                for lines in alllines:
                    data[i].append(lines)
        temp1 = getOccupiedState(data[0])
        temp2 = getOccupiedState(data[1])
        Dict3 = getDurationTime(temp1) + getDurationTime(temp2)
        sortedData = sorted(Dict3)
        berth1Occupied = getOccupiedTime(Dict3,traceObjects[0])
        berth2Occupied = getOccupiedTime(Dict3,traceObjects[1])

        if flag:
            #print intermediate steps for checking
            writerA = open(prefix+run[:-4]+'-Berth1occupied'+'.occ','w')
            writerB = open(prefix+run[:-4]+'-Berth2occupied'+'.occ','w')            
                
            writeOccupiedState(temp1,writerA)
            writeOccupiedState(temp2,writerB)                    
            writerBerthSorted = open(run[:-4]+'-sorted.occ','w')
            writerBerthUnsorted = open(run[:-4]+'-unsorted.occ','w')
            writeOccupiedState(sortedData,writerBerthSorted)
            writeOccupiedState(Dict3,writerBerthUnsorted)
        
        #sort based on start time
        #PERCENTAGE OF TIME THAT BOTH BERTHS ARE OCCUPIED
        for i in range(len(sortedData)):
            lineDiff = 0
            counter = 0
            if (sortedData[i][4]=='end' or sortedData[i][0]<initHours):
                pass
            #if the two lines are the same berth, cannot overlap
            elif (sortedData[i][1]==sortedData[i+1][1]):
                pass
            else:
                for j in range(1,len(sortedData[i:])):
                    if sortedData[i][endTimeIndex] < sortedData[i+j][startTimeIndex]:
                           lineDiff = j-1
                           break;
                #calculate the overlap between this line and the next line
                if lineDiff < 2:
                    if sortedData[i][berthNameIndex] == sortedData[i+lineDiff][berthNameIndex]:
                        pass
                    elif sortedData[i][endTimeIndex] > sortedData[i+lineDiff][endTimeIndex]:
                        overlapOccupied += sortedData[i+1][durationIndex]
                    elif sortedData[i+lineDiff][endTimeIndex] >= sortedData[i][endTimeIndex]:
                        overlapOccupied += sortedData[i][endTimeIndex]-sortedData[i+1][startTimeIndex]
                    else:
                        #WHY IN HERE?!
                        print str(lineDiff) + '\n' + str(sortedData[i][0])+','+str(sortedData[i][1])+','+str(sortedData[i][2])+','+str(sortedData[i][3])+','+str(sortedData[i][4])
                        print str(sortedData[i+1][0])+','+str(sortedData[i+1][1])+','+str(sortedData[i+1][2])+','+str(sortedData[i+1][3])+','+str(sortedData[i+1][4])
                #calculate the overlap between last line and this line
                elif lineDiff > 1:
                    for k in range(1,lineDiff+1):
                        if sortedData[1+k][4] == 'end':
                            print 'end file'
                        elif sortedData[i][berthNameIndex] == sortedData[i+k][berthNameIndex]:
                            print 'BERTH NAMES ARE EQUAL'
                        elif ((sortedData[i+k][endTimeIndex] < sortedData[i][endTimeIndex])and(sortedData[i+k][startTimeIndex] > sortedData[i][startTimeIndex])):
                            overlapOccupied += sortedData[i+k][durationIndex]
                        elif sortedData[i+k][endTimeIndex] >= sortedData[i][endTimeIndex]:
                            overlapOccupied += sortedData[i][endTimeIndex] - sortedData[i+k][startTimeIndex]
                        #elif sortedData[i][endTimeIndex] >= sortedData[i+k][endTimeIndex]:
                        #    overlapOccupied += sortedData[i+k][endTimeIndex] - sortedData[i+k][startTimeIndex]
                        else:
                            #WHY IN HERE?
                            print str(lineDiff) + '\n' + str(sortedData[i][0])+','+str(sortedData[i][1])+','+str(sortedData[i][2])+','+str(sortedData[i][3])+','+str(sortedData[i][4])
                            print str(sortedData[i+k][0])+','+str(sortedData[i+k][1])+','+str(sortedData[i+k][2])+','+str(sortedData[i+k][3])+','+str(sortedData[i+k][4])
                else:
                    #lineDiff = 0, no overlap
                    print "================================================================"
                    print str(sortedData[i][0])+','+str(sortedData[i][1])+','+str(sortedData[i][2])+','+str(sortedData[i][3])+','+str(sortedData[i][4])
                    print "================================================================"
        writer = open(prefix+run[:-4]+'.occ','w')
        writer.write('Percentage Occupied')
        writer.write('\n'+traceObjects[0]+' Occupied\t'+str(berth1Occupied)+'%')
        writer.write('\n'+traceObjects[1]+' Occupied\t'+str(berth2Occupied)+'%')
        writer.write('\n'+'Both Berths Occupied\t'+str(overlapOccupied/simEndTime*100)+'%')

#Data must be parsed using getOccupiedState first. This functions sums up all the "True" states and returns the list below.
#[Start Time, Object, Duration, Start Time + Duration, End Time (extra for checking but not used)]
#when it reaches the end of the file the list is: [Start Time, Object, Duration, Start Time + Duration, 'end'] -- this is end of the list and gives us an easy stopping condition.
def getDurationTime(myData):
    timeOccupied = 0.0
    startTime = 0.0
    endTime =0.0
    newEndTime = 0.0
    berthName = ''
    myList = []
    startTimeIndex = 0 #index from getOccupiedState(myData)
    berthNameIndex = 1 #index from getOccupiedState(myData)
    stateNameIndex = 2 #index from getOccupiedState(myData) 
    durationIndex = 3  #index from getOccupiedState(myData)
    endTimeIndex = 4   #index from getOccupiedState(myData)
    OccupiedIndex = 5  #index from getOccupiedState(myData)
    for i in range(len(myData)):
        if i < len(myData)-1:
            #4 combinations of True/False states
            #Current: False | Next: True
            #Beginning of a occupied group
                #Set the Start Time and Berth Name from the Next Line
            if not myData[i][OccupiedIndex] and myData[i+1][OccupiedIndex]:
                startTime = float(myData[i+1][startTimeIndex])
                berthName = myData[i+1][berthNameIndex]
            #Current: False | Next: False
                #DO NOTHING, Just incase - Reset Time to 0
            elif not myData[i][OccupiedIndex] and not myData[i+1][OccupiedIndex]:
                timeOccupied = 0
            #Current: True | Next: True
                #Add to time occupied
            elif myData[i][OccupiedIndex] and myData[i+1][OccupiedIndex]:
                timeOccupied += float(myData[i][durationIndex])
            #Current: True | Next: False
            #End of occupied group
                #Set End Time, Add Current duration to time occupied
                #Append and reset time occupied
            elif myData[i][OccupiedIndex] and not myData[i+1][OccupiedIndex]:
                endTime = float(myData[i][endTimeIndex])
                timeOccupied += float(myData[i][durationIndex])
                myList.append([startTime,berthName,timeOccupied,startTime+timeOccupied,endTime])
                timeOccupied=0
            #Just to make sure previous funcitons executed properly
            else:
                #shouldn't enter here
                print '=======================SOMETHING WRONG=========================='
        #last line of the file
        else:
            #if it ends during an occupied state
            if myData[i][OccupiedIndex] and myData[i-1][OccupiedIndex]:
                timeOccupied += float(myData[i][durationIndex])
                myList.append([startTime,berthName,timeOccupied,startTime+timeOccupied,myData[i][endTimeIndex]])
                myList.append([myData[i][startTimeIndex],myData[i][berthNameIndex],myData[i][OccupiedIndex],myData[i][startTimeIndex]+myData[i][durationIndex],'end'])
            #if it ends during an unoccupied state
            else:
                myList.append([myData[i][startTimeIndex],myData[i][berthNameIndex],myData[i][OccupiedIndex],myData[i][startTimeIndex]+myData[i][durationIndex],'end'])
    return myList

#gets the occupied percentage for an object. Data must be parsed using 1) getOccupiedState then 2) getDurationTime
#before using this function
def getOccupiedTime(myData, myObject):
    sumOccupied = 0.0
    for i in myData:
        if (isinstance(i[0], float) and i[1] == myObject and (i[4] != 'end' and i[0]>=initHours)):
            sumOccupied += i[2]
    percentOccupied = sumOccupied/simEndTime*100
    return percentOccupied

#reads state and adds a boolean column. True = Occupied, False = Not Occupied
#Returns: [Start Time, Object, State, Duration, End Time, True/False]
#The start of when a berth is occupied is the pre-handling time state. If a vessel does not enter this state, berth occupancy will be 0
#States Occupied is everything between Pre-Handling to Post-Handling (and Wait for Conditions to Clear Berth).
def getOccupiedState(myData):
    myDict = []
    startTime = 0.0 
    duration = 0.0
    endTime = 0.0
    berthName = ''
    stateName = ''
    for i in range(len(myData)):
        #TLS outputs in this format
        #To generalize this
        searchStates = re.match('([0-9.]+)  (BPBerth[12]).setState\( "([a-zA-Z -0-9]+)" \) dt = ([0-9.]+)',myData[i])
        if searchStates and searchStates.group(1)>=initHours:
            startTime = float(searchStates.group(1))
            berthName = searchStates.group(2)
            stateName = searchStates.group(3)
            duration = float(searchStates.group(4))
            endTime = startTime+duration
            if (searchStates.group(3) in states):
                myDict.append([startTime,berthName,stateName,duration,endTime,True])
            else:
                myDict.append([startTime,berthName,stateName,duration,endTime,False])
    return myDict

#write an array to file.
def writeOccupiedState(myData,myWriter):
    for line in myData:
        for items in line:
            myWriter.write(str(items)+'\t')
        myWriter.write('\n')

main(flag)
