__author__ = 'sware'

from Tkinter import *
from ttk import *
import tkFileDialog
import os
import shutil
import tkSimpleDialog
import subprocess

from susapps import make_abstraction, make_add_tau_event, make_aggregated_supervisor, make_aggregated_time_optimal_supervisor, \
    make_compute_shortest_path, make_controllability_check, make_dot, make_feasible_supervisor, make_get_size,\
    make_get_weighted_size, make_greedy_time_optimal_supervisor_correctly, make_language_equivalence_test,\
    make_language_inclusion_test, make_minimization, make_natural_projection, make_nonconflicting_check, make_observer_check,\
    make_optimal_weighted_supervisor, make_product, make_remove_tau_event, make_remove_weight, make_reset_weighted,\
    make_sequential_abstraction, make_supervisor, make_tau_abstracted_supervisor, make_tau_abstraction,\
    make_time_optimal_accepting_trace, make_time_optimal_supervisor_from_weighted, make_time_optimal_supervisor, \
    make_trim, make_walk,\
    make_weighted_dot, make_weighted_product, make_weighted_projection, make_weighted_supervisor
from automata import weighted_structure, data_structure, collection, frontend


root = Tk()

class filewrapper(object):

    def __init__(self, ofile):
        self.wrappedfile = ofile
        self.strvar = StringVar()
        self.strvar.set(str(ofile))

project_folder = ['']

applist = [('make abstraction', make_abstraction.MakeAbstractionApplication()),
           ('make add tau event', make_add_tau_event.MakeAddTauEventApplication()),
           ('make aggregated supervisor', make_aggregated_supervisor.MakeTauAbstractedSupervisorApplication()),
           ('make aggregated time optimal supervisor', make_aggregated_time_optimal_supervisor.MakeAggregatedTimeOptimalSupervisor()),
           ('make compute shortest path', make_compute_shortest_path.ComputeShortestPathApplication()),
           ('make controllability check', make_controllability_check.MakeControllabilityCheckApplication()),
           ('make dot', make_dot.MakeDotApplication()),
           ('make feasible supervisor', make_feasible_supervisor.MakeFeasibleSupervisorApplication()),
           ('make get size', make_get_size.MakeGetSizeApplication()),
           ('make get weighted size', make_get_weighted_size.MakeWeightedSizeApplication()),
           ('make greedy time optimal supervisor correctly', make_greedy_time_optimal_supervisor_correctly.MakeGreedyTimeOptimalSupervisorCorrectlyApplication()),
           ('make language inclusion test', make_language_inclusion_test.TestLanguageInclusionApplication()),
           ('make language equivalence test', make_language_equivalence_test.TestLanguageEquivalenceApplication()),
           ('make minimization', make_minimization.MakeMinimizationApplication()),
           ('make natural projection', make_natural_projection.MakeNaturalProjectionApplication()),
           ('make nonconflicting check', make_nonconflicting_check.MakeNonConflictingCheckApplication()),
           ('make observer check', make_observer_check.MakeObserverCheckApplication()),
           ('make optimal weighted supervisor', make_optimal_weighted_supervisor.MakeOptimalWeightedSupervisorApplication()),
           ('make product', make_product.MakeProductApplication()),
           ('make remove tau event', make_remove_tau_event.MakeRemoveTauEventApplication()),
           ('make remove weight', make_remove_weight.RemoveWeightsApplication()),
           ('make reset weight', make_reset_weighted.ResetWeightsApplication()),
           ('make sequential abstraction', make_sequential_abstraction.MakeSequentialAbstractionApplication()),
           ('make supervisor', make_supervisor.MakeSupervisorApplication()),
           ('make tau abstracted supervisor', make_tau_abstracted_supervisor.MakeTauAbstractedSupervisorApplication()),
           ('make time optimal accepting trace', make_time_optimal_accepting_trace.MakeTimeOptimalAcceptingTrace()),
           ('make time optimal accepting trace from weighted', make_time_optimal_supervisor_from_weighted.MakeTimeOptimalSupervisorFromWeightedApplication()),
           ('make time optimal supervisor', make_time_optimal_supervisor.MakeTimeOptimalSupervisorApplication()),
           ('make time optimal supervisor from weighted', make_time_optimal_supervisor_from_weighted.MakeTimeOptimalSupervisorFromWeightedApplication()),
           ('make trim', make_trim.MakeTrimApplication()),
           ('make walk', make_walk.MakeWalk()),
           ('make weighted dot', make_weighted_dot.MakeWeightedDotApplication()),
           ('make weighted product', make_weighted_product.MakeWeightedProductApplication()),
           ('make weighted projection', make_weighted_projection.MakeWeightedProjectionApplication()),
           ('make weighted supervisor', make_weighted_supervisor.MakeWeightedSupervisorApplication())]

dirs = ['/automata', '/misc']
weighted_template = os.path.curdir + '/gui/weighted_template.txt'
print weighted_template
unweighted_template = os.path.curdir + '/gui/aut_template.txt'
print unweighted_template

treeviewweighted = Treeview(root)
treeviewweighted.pack(side=LEFT,fill=Y)
weightscroll = Scrollbar(root)
weightscroll.pack(side=LEFT, fill=Y)
weightscroll.configure(command=treeviewweighted.yview)
treeviewmisc = Treeview(root)
treeviewmisc.pack(side=LEFT,fill=Y)
miscscroll = Scrollbar(root)
miscscroll.pack(side=LEFT,fill=Y)
miscscroll.configure(command=treeviewmisc.yview)

plants = []
specs = []
out = []
misc = []

treeidtopathweighted = {}
treeidtopathunweighted = {}
treeidtopathmisc = {}

def buildTree(root, path, treeview, idmap, suffix):
    print root, path
    for file in os.listdir(path):
        print file, os.path.isdir(path + '/' + file)
        if os.path.isdir(path + '/' + file):
            id = treeview.insert(root, 'end', text=file)
            idmap[id] = path + '/' + file
            buildTree(id, path + '/' + file, treeview, idmap, suffix)
        elif file.endswith(suffix):
            idmap[treeview.insert(root, 'end', text=file)] = path + '/' + file

def cleartrees():
    treeviewweighted.delete(*treeviewweighted.get_children())
    treeidtopathweighted.clear()
    treeviewmisc.delete(*treeviewmisc.get_children())
    treeidtopathmisc.clear()

def loadpath(di):
    cleartrees()
    project_folder[0] = di
    for dir in dirs:
        if not os.path.exists(di + dir):
            os.mkdir(di + dir)
        if not os.path.exists(di + dir + '/plants'):
            os.mkdir(di + dir + '/plants')
        if not os.path.exists(di + dir + '/specs'):
            os.mkdir(di + dir + '/specs')
    if not os.path.exists(di + '/misc'):
        os.mkdir(di + '/misc')
    plantdir = di + dirs[0]
    buildTree('', plantdir, treeviewweighted, treeidtopathweighted, '.cfg')
    treeidtopathweighted[''] = plantdir
    #treeview.pack(side=LEFT)
    plantdir = di + dirs[1]
    buildTree('', plantdir, treeviewmisc, treeidtopathmisc, '.cfg')
    treeidtopathunweighted[''] = plantdir
    #buildTree('', plantdir)

def NewCommand():
    di = tkFileDialog.askdirectory()
    loadpath(di)

menubar = Menu(root)

filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label='New', command=NewCommand)
filemenu.add_command(label='Reload', command=lambda :loadpath(project_folder[0]))

menubar.add_cascade(label='File', menu=filemenu)

root.config(menu=menubar)

def new_fold(prefix, treeview, dictmap):
    if activepath[0] == '':
        di = project_folder[0] + prefix
    else:
        di = dictmap[activepath[0]]
        if not os.path.isdir(di):
            di = dictmap[treeview.parent(activepath[0])]
    nname = tkSimpleDialog.askstring('new folder', 'enter folder name')
    if not os.path.exists(di + '/' + nname):
        os.mkdir(di + '/' + nname)
    loadpath(project_folder[0])

def new_aut(prefix, treeview, dictmap, template):
    if activepath[0] == '':
        di = project_folder[0] + prefix
    else:
        di = dictmap[activepath[0]]
        if not os.path.isdir(di):
            di = dictmap[treeview.parent(activepath[0])]
    nname = tkSimpleDialog.askstring('new aut', 'enter folder name')
    if not os.path.exists('"' + di + '/' + nname + '"'):
        print 'out', '"' + di + '/' + nname + '.cfg"'
        shutil.copyfile(template, di + '/' + nname + '.cfg')
    loadpath(project_folder[0])
    #subprocess.call(["start", '{}/{}.cfg'.format(di, nname)])
    os.startfile('{}/{}.cfg'.format(di, nname))
    #os.system('start "'  + di + '/' + nname + '.cfg"')

def new_text_file(prefix, treeview, dictmap):
    if activepath[0] == '':
        di = project_folder[0] + prefix
    else:
        di = dictmap[activepath[0]]
        if not os.path.isdir(di):
            di = dictmap[treeview.parent(activepath[0])]
    nname = tkSimpleDialog.askstring('new aut', 'enter folder name')
    if not os.path.exists(di + '/' + nname):
        handle = file(di + '/' + nname + '.txt')
        handle.close()
    loadpath(project_folder[0])
    os.startfile('{}/{}.txt'.format(di, nname))
    #os.system('start '  + di + '/' + nname + '.txt')

def delete(dictmap):
    if activepath[0] == '':
        return
    else:
        di = dictmap[activepath[0]]
        if os.path.isdir(di):
            shutil.rmtree(di)
        else:
            os.remove(di)
    loadpath(project_folder[0])

def visualize(dictmap):
    di = dictmap[activepath[0]]
    if os.path.isdir(di):
        return
    handle = file(di, 'r')
    firstline = handle.readline()
    handle.close()
    if '[weighted-automaton]' in firstline:
        print 'weighted'
        loader = weighted_structure.load_automaton
    else:
        print
        loader = data_structure.load_automaton
    waut = loader(collection.Collection(), di)
    waut.save_as_dot(di + '.dot')
    os.startfile('{}.dot'.format(di))
    #os.system('start ' + di + '.dot')

weightedmenu = Menu(root, tearoff=0)
weightedmenu.add_command(label="New Folder", command=lambda:new_fold('/automaton', treeviewweighted, treeidtopathweighted))
weightedmenu.add_command(label="New Weighted Automaton", command=lambda:new_aut('/automaton', treeviewweighted, treeidtopathweighted, weighted_template))
weightedmenu.add_command(label="New Automaton", command=lambda:new_aut('/automaton', treeviewweighted, treeidtopathweighted, unweighted_template))
weightedmenu.add_command(label="Delete", command=lambda:delete(treeidtopathweighted))
weightedmenu.add_command(label="Visualize", command=lambda:visualize(treeidtopathweighted))

unweightedmenu = Menu(root, tearoff=0)
unweightedmenu.add_command(label="New Folder", command=lambda:new_fold('/misc', treeviewmisc, treeidtopathmisc))
unweightedmenu.add_command(label="New Text File", command=lambda:new_text_file('/unweighted', treeviewmisc, treeidtopathmisc))
unweightedmenu.add_command(label="Delete", command=lambda:delete(treeidtopathmisc))



activepath = ['']

def popup(menu, treeview, event):
    print 'popup'
    activepath[0] = treeview.identify_row(event.y)
    print treeviewweighted.identify_row(event.y), event.x_root, event.y_root
    menu.post(event.x_root, event.y_root)

def open(event, treeview, dictmap):
    print 'open'
    pa = treeview.identify_row(event.y)
    di = dictmap[pa]
    print di, os.path.isdir(di)
    if os.path.isdir(di):
        return
    print 'start ' + '\"{}\"'.format(di)
    print di
    #subprocess.call(["start", di])
    os.startfile(di)
    #os.system(r'"start ' + '{}"'.format(di))

dragstrings = []

def clearlist(li):
    while li:
        li.pop()

def getselecteditems(treeview, dictmap, selection):
    clearlist(selection)
    for element in treeview.selection():
        path = dictmap[element]
        print path
        if not os.path.isdir(path):
            print path
            selection.append(path)

treeviewweighted.bind('<Button-1>', lambda event: getselecteditems(treeviewweighted,
                                                                   treeidtopathweighted,
                                                                   dragstrings))
root.bind('<ButtonRelease-1>', lambda event: clearlist(dragstrings))

# attach popup to frame
treeviewweighted.bind("<Button-3>", lambda event: popup(weightedmenu, treeviewweighted, event))
treeviewweighted.bind("<Double-1>", lambda event: open(event, treeviewweighted, treeidtopathweighted))
treeviewmisc.bind("<Double-1>", lambda event: open(event, treeviewmisc, treeidtopathmisc))

appframe = Frame(root)
appframe.pack(side=RIGHT)
appvar = StringVar()
appvar.set('make abstraction')
appmap = {}
cmdmap = {}
for tup in applist:
    appmap[tup[0]] = tup[1]
    tup[1].add_options()
print appmap
options = OptionMenu(appframe, appvar, appvar.get(), *tuple([tup[0] for tup in applist]))
options.pack(side=TOP)

def exbuttoncmd():
    ap = appmap[appvar.get()]
    args = {}
    for cmd in cmdmap:
        args[cmd] = cmdmap[cmd].get()
    ap.main(args)

def optionchanged(a,b,c):
    setupappframe()

appvar.trace('w', optionchanged)
desc = StringVar()
label = Label(appframe, textvariable=desc)
label.pack(side=TOP)
exbutton = Button(text="Execute", command=exbuttoncmd)
exbutton.pack(side=BOTTOM)
appframeframes = []

def getFiles(treeview, dictmap,v):
    nTK = Tk()
    listoffiles = []
    dictmap = {}
    dictmap[''] = project_folder[0] + '/automata'
    treeview = Treeview(nTK)
    buildTree('', project_folder[0] + '/automata', treeview, dictmap, '.cfg')
    treeview.pack(side=LEFT)
    def collectfiles():
        for element in treeview.selection():
            path = dictmap[element]
            print path
            if not os.path.isdir(path):
                print path
                listoffiles.append(path)
        v.set(','.join(listoffiles))
    button = Button(nTK, text='ex', command=collectfiles)
    button.pack(side=BOTTOM)

def get_path(type, v):
    if type == frontend.EXIST_AUT:
        v.set(tkFileDialog.askopenfilename(initialdir=project_folder[0] + '/automata'))
    if type == frontend.AUT or type == frontend.DOT:
        v.set(tkFileDialog.asksaveasfilename(initialdir=project_folder[0] + '/automata'))
    if type == frontend.AUTLIST:
        getFiles(treeviewweighted, treeidtopathweighted, v)


def setupappframe():
    while appframeframes:
        appframeframes.pop().pack_forget()
    app = appvar.get()
    app = appmap[app]
    desc.set(app.description)
    print app.parms
    for cmd in app.parms:
        print cmd
        fr = Frame(appframe)
        v = StringVar()
        textbox = Entry(fr,textvariable=v)
        textbox.pack(side=RIGHT)
        button = Button(fr, text='open', command=lambda kind=cmd.kind, v=v: get_path(kind, v))
        button.pack(side=RIGHT)
        #textbox.bind('<ButtonRelease-1>', appendfiles)
        lab = Label(fr, text=cmd.name)
        lab.pack(side=LEFT)
        fr.pack(side=TOP)
        cmdmap[cmd.name] = v
        appframeframes.append(fr)

setupappframe()
NewCommand()

root.mainloop()
