#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.7.2 on Tue Jun 07 12:40:46 2016
#
# Copyright (c) 2016, Amane Tanaka
# 03.08.2016 initial vaersion
 
import wx
import wx.grid

# begin wxGlade: dependencies
import gettext
# end wxGlade
import os
import uuid
import subprocess
import sys
import zipfile

# begin wxGlade: extracode
# end wxGlade


class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        wx.Frame.__init__(self, *args, **kwds)
        self.modelGrid = wx.grid.Grid(self, wx.ID_ANY, size=(1, 1))
        self.inputGrid = wx.grid.Grid(self, wx.ID_ANY, size=(1, 1))
        self.outputGrid = wx.grid.Grid(self, wx.ID_ANY, size=(1, 1))
        self.fmuNameButton = wx.Button(self, wx.ID_ANY, _("FMU Name:"), style=wx.BORDER_NONE | wx.BU_EXACTFIT)
        self.fmuNameText = wx.TextCtrl(self, wx.ID_ANY, _("bouncingBall"))
        self.ipAdressButton = wx.Button(self, wx.ID_ANY, _("GUID:"), style=wx.BORDER_NONE | wx.BU_EXACTFIT)
        self.guidText = wx.TextCtrl(self, wx.ID_ANY, _("{8c4e810f-3df3-4a00-8276-176fa3c9f003}"))
        self.button_7 = wx.Button(self, wx.ID_ANY, _("IP Address:"), style=wx.BORDER_NONE | wx.BU_EXACTFIT)
        self.ipAddressText = wx.TextCtrl(self, wx.ID_ANY, _("192.168.0.3"))
        self.label_22 = wx.StaticText(self, wx.ID_ANY, _("lPort Number: "))
        self.portNumberText = wx.TextCtrl(self, wx.ID_ANY, _("9999"))
        self.startTimeLabel = wx.StaticText(self, wx.ID_ANY, _("Start Time: "))
        self.startTimeText = wx.TextCtrl(self, wx.ID_ANY, _("0"))
        self.stopTimeLabel = wx.StaticText(self, wx.ID_ANY, _("Stop Time: "))
        self.stopTimeText = wx.TextCtrl(self, wx.ID_ANY, _("10"))
        self.label_18 = wx.StaticText(self, wx.ID_ANY, _("Tolerance: "))
        self.toleranceText = wx.TextCtrl(self, wx.ID_ANY, _("1.0e-4"))
        self.clearButton = wx.Button(self, wx.ID_CLEAR, "")
        self.reloadButton = wx.Button(self, wx.ID_ANY, _("&Reload"))
        self.saveButton = wx.Button(self, wx.ID_SAVE, "")
        self.generateButton = wx.Button(self, wx.ID_ANY, _("&Generate FMU"))
        self.button_1 = wx.Button(self, wx.ID_CLOSE, "")

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_BUTTON, self.copyName, self.fmuNameButton)
        self.Bind(wx.EVT_BUTTON, self.generateGuid, self.ipAdressButton)
        self.Bind(wx.EVT_BUTTON, self.findMyIP, self.button_7)
        self.Bind(wx.EVT_BUTTON, self.clear, self.clearButton)
        self.Bind(wx.EVT_BUTTON, self.reload, self.reloadButton)
        self.Bind(wx.EVT_BUTTON, self.save, self.saveButton)
        self.Bind(wx.EVT_BUTTON, self.generate, self.generateButton)
        self.Bind(wx.EVT_BUTTON, self.closeEnd, self.button_1)
        # end wxGlade

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle(_("FMU CS Generator"))
        self.SetSize((583, 585))
        self.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
        self.modelGrid.CreateGrid(10, 2)
        self.modelGrid.SetRowLabelSize(30)
        self.modelGrid.SetColLabelValue(0, _("Item"))
        self.modelGrid.SetColSize(0, 110)
        self.modelGrid.SetColLabelValue(1, _("Value"))
        self.modelGrid.SetColSize(1, 355)
        self.modelGrid.SetMinSize((532, 86))
        self.inputGrid.CreateGrid(30, 2)
        self.inputGrid.SetRowLabelSize(30)
        self.inputGrid.SetColLabelValue(0, _("Input Variable"))
        self.inputGrid.SetColSize(0, 110)
        self.inputGrid.SetColLabelValue(1, _("Start Value"))
        self.inputGrid.SetColSize(1, 100)
        self.inputGrid.SetMinSize((261, 123))
        self.outputGrid.CreateGrid(30, 2)
        self.outputGrid.SetRowLabelSize(30)
        self.outputGrid.SetColLabelValue(0, _("Output Variable"))
        self.outputGrid.SetColSize(0, 110)
        self.outputGrid.SetColLabelValue(1, _("Start Value"))
        self.outputGrid.SetColSize(1, 100)
        self.outputGrid.SetMinSize((261, 123))
        self.fmuNameText.SetMinSize((270, -1))
        self.guidText.SetMinSize((270, -1))
        self.ipAddressText.SetMinSize((270, -1))
        self.portNumberText.SetMinSize((270, -1))
        self.startTimeText.SetMinSize((100, -1))
        self.stopTimeText.SetMinSize((100, -1))
        self.toleranceText.SetMinSize((100, -1))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_8 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_7 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Default Experiment")), wx.HORIZONTAL)
        grid_sizer_4 = wx.FlexGridSizer(3, 2, 0, 0)
        sizer_6 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("FMU Information")), wx.HORIZONTAL)
        grid_sizer_5 = wx.FlexGridSizer(4, 2, 0, 0)
        sizer_2 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Exchange Variables")), wx.HORIZONTAL)
        sizer_4 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, _("Model Information")), wx.HORIZONTAL)
        sizer_4.Add(self.modelGrid, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 2)
        sizer_1.Add(sizer_4, 1, wx.ALL, 10)
        sizer_2.Add(self.inputGrid, 1, wx.ALL | wx.EXPAND, 2)
        sizer_2.Add(self.outputGrid, 1, wx.ALL | wx.EXPAND, 2)
        sizer_1.Add(sizer_2, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)
        grid_sizer_5.Add(self.fmuNameButton, 0, wx.ALIGN_RIGHT, 0)
        grid_sizer_5.Add(self.fmuNameText, 0, 0, 0)
        grid_sizer_5.Add(self.ipAdressButton, 0, wx.ALIGN_RIGHT, 0)
        grid_sizer_5.Add(self.guidText, 0, 0, 0)
        grid_sizer_5.Add(self.button_7, 0, wx.ALIGN_RIGHT, 0)
        grid_sizer_5.Add(self.ipAddressText, 0, 0, 0)
        grid_sizer_5.Add(self.label_22, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 0)
        grid_sizer_5.Add(self.portNumberText, 0, 0, 0)
        sizer_6.Add(grid_sizer_5, 1, 0, 0)
        sizer_5.Add(sizer_6, 0, wx.ALL | wx.SHAPED, 2)
        grid_sizer_4.Add(self.startTimeLabel, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_4.Add(self.startTimeText, 0, 0, 0)
        grid_sizer_4.Add(self.stopTimeLabel, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_4.Add(self.stopTimeText, 0, 0, 0)
        grid_sizer_4.Add(self.label_18, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_4.Add(self.toleranceText, 0, 0, 0)
        sizer_7.Add(grid_sizer_4, 1, 0, 0)
        sizer_5.Add(sizer_7, 0, wx.ALL, 2)
        sizer_1.Add(sizer_5, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)
        sizer_8.Add((20, 0), 1, wx.ALL | wx.EXPAND, 10)
        sizer_8.Add(self.clearButton, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        sizer_8.Add(self.reloadButton, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        sizer_8.Add(self.saveButton, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        sizer_8.Add(self.generateButton, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        sizer_8.Add(self.button_1, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        sizer_1.Add(sizer_8, 0, wx.ALL | wx.EXPAND, 10)
        self.SetSizer(sizer_1)
        self.Layout()
        # end wxGlade

    def copyName(self, event):  # wxGlade: MyFrame.<event_handler>
        #print "Event handler 'copyName' not implemented!"
        self.copyModelName()        
        event.Skip()

    def generateGuid(self, event):  # wxGlade: MyFrame.<event_handler>
        #print "Event handler 'generateGuid' not implemented!"
        self.newGUID()        
        event.Skip()

    def findMyIP(self, event):  # wxGlade: MyFrame.<event_handler>
        print "Event handler 'findMyIP' not implemented!"
        event.Skip()

    def clear(self, event):  # wxGlade: MyFrame.<event_handler>
        #print "Event handler 'clear' not implemented!"
        self.clearCFG()        
        event.Skip()

    def reload(self, event):  # wxGlade: MyFrame.<event_handler>
        #print "Event handler 'reload' not implemented!"
        self.loadCFG()        
        event.Skip()

    def save(self, event):  # wxGlade: MyFrame.<event_handler>
        #print "Event handler 'save' not implemented!"
        self.saveCFG()        
        event.Skip()

    def generate(self, event):  # wxGlade: MyFrame.<event_handler>
        #print "Event handler 'generate' not implemented!"
        self.saveCFG() 
        self.makeFmuDir()		
        self.generateXML()
        self.generateModelH()
        self.ganerateVariablesC()
        self.makeDLL()
        self.zip_directory("fmu")
        print "FMU is generated successfully!"
        event.Skip()

    def closeEnd(self, event):  # wxGlade: MyFrame.<event_handler>
        #print "Event handler 'closeEnd' not implemented!"
        self.Close(True)        
        event.Skip()

    def makeFmuDir(self):
        if not os.path.isdir("fmu"):
            os.mkdir("fmu")
            os.mkdir("fmu\\binaries")
            os.mkdir("fmu\\binaries\\win32")
            os.mkdir("fmu\\binaries\\win64")
            os.mkdir("fmu\\documentation")
            os.mkdir("fmu\\resources")
            os.mkdir("fmu\\sources")

    def saveCFG(self):
        f = open("fmuchick.cfg","w")
        f.write("[model]\n")
        for i in range(0, self.modelGrid.NumberRows):
            item = self.modelGrid.GetCellValue(i,0)
            value = self.modelGrid.GetCellValue(i,1)
            if len(value) > 0:
                f.write(item + "\n")
                f.write(value + "\n")
        f.write("\n")
        f.write("[input]\n")                
        for i in range(0, self.inputGrid.NumberRows):
            variableName = self.inputGrid.GetCellValue(i,0)
            startValue = self.inputGrid.GetCellValue(i,1)
            if len(variableName) > 0:
                f.write(variableName + "\n")
                f.write(startValue + "\n")
        f.write("\n")
        f.write("[output]\n")
        for i in range(0, self.outputGrid.NumberRows):
            variableName = self.outputGrid.GetCellValue(i,0)
            startValue = self.outputGrid.GetCellValue(i,1)
            if len(variableName) > 0:
                f.write(variableName + "\n")
                f.write(startValue + "\n")        
        f.write("\n")
        f.write("[fmu]\n")
        f.write(self.fmuNameText.GetValue() + "\n")
        f.write(self.guidText.GetValue() + "\n")
        f.write(self.ipAddressText.GetValue() + "\n")
        f.write(self.portNumberText.GetValue() + "\n")
        f.write("\n")
        f.write("[experiment]\n")
        f.write(self.startTimeText.GetValue() + "\n")
        f.write(self.stopTimeText.GetValue() + "\n")
        f.write(self.toleranceText.GetValue() + "\n")
        f.write("\n")
        f.close()

    def clearCFG(self):
        for i in range(0, self.modelGrid.NumberRows):
            for j in range(0, self.modelGrid.NumberCols):
                self.modelGrid.SetCellValue(i,j,"")
        for i in range(0, self.inputGrid.NumberRows):
            for j in range(0, self.inputGrid.NumberCols):
                self.inputGrid.SetCellValue(i,j,"")
        for i in range(0, self.outputGrid.NumberRows):
            for j in range(0, self.outputGrid.NumberCols):
                self.outputGrid.SetCellValue(i,j,"")
        self.fmuNameText.SetValue("")
        self.guidText.SetValue("")
        self.ipAddressText.SetValue("")
        self.portNumberText.SetValue("")
        self.startTimeText.SetValue("")
        self.stopTimeText.SetValue("")
        self.toleranceText.SetValue("")

    def loadCFG(self):
        f = open("fmuchick.cfg","r")
        l = f.readline()
        while l:
            l = l.rstrip()
            if l == "[model]":
                item = f.readline()
                item = item.rstrip()
                i = 0
                while len(item)>0:
                    value = f.readline()
                    value = value.rstrip()
                    self.modelGrid.SetCellValue(i,0,item)
                    self.modelGrid.SetCellValue(i,1,value)
                    i += 1
                    item = f.readline()
                    item = item.rstrip()
            if l == "[input]":
                item = f.readline()
                item = item.rstrip()
                i = 0
                while len(item)>0:
                    value = f.readline()
                    value = value.rstrip()
                    self.inputGrid.SetCellValue(i,0,item)
                    self.inputGrid.SetCellValue(i,1,value)
                    i += 1
                    item = f.readline()
                    item = item.rstrip()
            if l == "[output]":
                item = f.readline()
                item = item.rstrip()
                i = 0
                while len(item)>0:
                    value = f.readline()
                    value = value.rstrip()
                    self.outputGrid.SetCellValue(i,0,item)
                    self.outputGrid.SetCellValue(i,1,value)
                    i += 1
                    item = f.readline()
                    item = item.rstrip()
            if l == "[fmu]":
                n = f.readline()
                n = n.rstrip()
                self.fmuNameText.SetValue(n)
                n = f.readline()
                n = n.rstrip()
                self.guidText.SetValue(n)
                n = f.readline()
                n = n.rstrip()
                self.ipAddressText.SetValue(n)
                n = f.readline()
                n = n.rstrip()
                self.portNumberText.SetValue(n)
            if l == "[experiment]":
                n = f.readline()
                n = n.rstrip()
                self.startTimeText.SetValue(n)
                n = f.readline()
                n = n.rstrip()
                self.stopTimeText.SetValue(n)
                n = f.readline()
                n = n.rstrip()
                self.toleranceText.SetValue(n)               
            #print l
            l = f.readline()
        f.close()

    def copyModelName(self):
        name = self.modelGrid.GetCellValue(0,1)
        if len(name)>0:
            self.fmuNameText.SetValue(name)
    
    def generateXML(self):
        f = open("fmu/modelDescription.xml","w")
        f.write("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n")
        f.write("<fmiModelDescription\n")
        f.write("  fmiVersion=\"1.0\"")
        f.write("  modelName=\"" + self.fmuNameText.GetValue() + "\"\n")
        f.write("  modelIdentifier=\"" + self.fmuNameText.GetValue() + "\"\n")
        f.write("  guid=\"" + self.guidText.GetValue() + "\"\n")
        f.write("  numberOfContinuousStates=\"0\"\n")
        f.write("  numberOfEventIndicators=\"0\">\n")
        f.write("  <ModelVariables>\n")
        vr = 0
        for i in range(0, self.inputGrid.NumberRows):
            name = self.inputGrid.GetCellValue(i,0)
            start = self.inputGrid.GetCellValue(i,1)
            if (len(name)>0) & (len(start)>0):
                f.write("    <ScalarVariable name=\"" + name + "\" valueReference=\"" + str(vr) +"\" description=\"input variable\" causality=\"input\">\n" )
                f.write("      <Real start=\"" + start + "\" fixed=\"true\"/>\n")
                f.write("    </ScalarVariable>\n")
                vr += 1
        for i in range(0, self.outputGrid.NumberRows):
            name = self.outputGrid.GetCellValue(i,0)
            start = self.outputGrid.GetCellValue(i,1)
            if (len(name)>0) & (len(start)>0):
                f.write("    <ScalarVariable name=\"" + name + "\" valueReference=\"" + str(vr) +"\" description=\"output variable\" causality=\"output\">\n" )
                f.write("      <Real start=\"" + start + "\" fixed=\"true\"/>\n")
                f.write("    </ScalarVariable>\n")
                vr += 1
        f.write("  </ModelVariables>\n")
        f.write("  <Implementation>\n")
        f.write("    <CoSimulation_StandAlone>\n")
        f.write("      <Capabilities\n")
        f.write("        canHandleVariableCommunicationStepSize=\"false\"\n")
        f.write("        canHandleEvents=\"false\"/>\n")
        f.write("    </CoSimulation_StandAlone>\n")
        f.write("  </Implementation>\n")
        f.write("</fmiModelDescription>\n")
        f.close()

    def newGUID(self):
        self.guidText.SetValue("{"+str(uuid.uuid4())+"}")

    def makeDLL(self):
        ret = subprocess.call("buildDll.bat "+self.fmuNameText.GetValue(), shell=True)
        print ret

    def zip_directory(self,path):
        zip_targets = []
        base = os.path.basename(path)
        zipfilepath = os.path.abspath('%s.zip' % base)
        for dirpath, dirnames, filenames in os.walk(path):
            for filename in filenames:
                filepath = os.path.join(dirpath, filename)
                if filepath == zipfilepath:
                    continue
                arc_name = os.path.relpath(filepath, os.path.dirname(path))
                arc_name = arc_name[4:]
                print filepath, arc_name
                zip_targets.append((filepath, arc_name))
            for dirname in dirnames:
                filepath = os.path.join(dirpath, dirname)
                arc_name = os.path.relpath(filepath, os.path.dirname(path)) + os.path.sep
                arc_name = arc_name[4:]                
                print filepath, arc_name
                zip_targets.append((filepath, arc_name))
        zip = zipfile.ZipFile(zipfilepath, 'w')
        for filepath, name in zip_targets:
            zip.write(filepath, name)
        zip.close()
        os.rename("fmu.zip",str(self.fmuNameText.GetValue())+".fmu")

    def generateModelH(self):
        ninfo = 0
        for i in range(0, self.modelGrid.NumberRows):
            if len(self.modelGrid.GetCellValue(i,1)) > 0:
                ninfo += 1
        ninput = 0
        for i in range(0, self.inputGrid.NumberRows):
            if len(self.inputGrid.GetCellValue(i,0)) > 0:
                ninput += 1
        noutput = 0
        for i in range(0, self.outputGrid.NumberRows):
            if len(self.outputGrid.GetCellValue(i,0))>0:
                noutput += 1
        nreal = ninput + noutput
        f = open("model.h","w")
        f.write("// define class name and unique id\n")
        f.write("#define MODEL_IDENTIFIER "+str(self.fmuNameText.GetValue())+"\n")
        f.write("#define MODEL_GUID \""+str(self.guidText.GetValue())+"\"\n")
        f.write("\n")
        f.write("// define model size\n")
        f.write("#define NUMBER_OF_REALS "+str(nreal)+"\n")
        f.write("#define NUMBER_OF_INTEGERS 0\n")
        f.write("#define NUMBER_OF_BOOLEANS 0\n")
        f.write("#define NUMBER_OF_STRINGS 0\n")
        f.write("#define NUMBER_OF_STATES 0\n")
        f.write("#define NUMBER_OF_EVENT_INDICATORS 0\n")
        f.write("#define NUMBER_OF_REAL_INPUTS "+str(ninput)+"\n")
        f.write("#define NUMBER_OF_REAL_OUTPUTS "+str(noutput)+"\n")
        f.write("#define NUMBER_OF_ITEMS "+str(ninfo)+"\n")
        f.write("\n")
        f.write("// network connection parametera\n")
        f.write("#define PORT "+str(self.portNumberText.GetValue())+"\n")
        f.write("#define IPADDR \""+str(self.ipAddressText.GetValue())+"\"\n")
        f.write("\n")
        f.write("#include <stdio.h>\n")
        f.write("#include <winsock2.h>\n")
        f.write("#include <ws2tcpip.h>\n")
        f.close()

    def ganerateVariablesC(self):
        f = open("variables.c","w")
        f.write("void defineVariables(){\n")
        for i in range(0, self.modelGrid.NumberRows):
            if len(self.modelGrid.GetCellValue(i,1)) > 0:
                f.write("    strcpy(itemName["+str(i)+"], \""+str(self.modelGrid.GetCellValue(i,0))+"\");\n")
                f.write("    strcpy(itemValue["+str(i)+"], \""+str(self.modelGrid.GetCellValue(i,1))+"\");\n")
        f.write("\n")
        for i in range(0, self.inputGrid.NumberRows):
            if len(self.inputGrid.GetCellValue(i,0)) > 0:
                f.write("    strcpy(inputName["+str(i)+"], \""+str(self.inputGrid.GetCellValue(i,0))+"\");\n")
                if len(self.inputGrid.GetCellValue(i,1)) > 0:                
                    f.write("    inputValue["+str(i)+"] = "+str(self.inputGrid.GetCellValue(i,1))+";\n")                
                else:
                    f.write("    inputValue["+str(i)+"] = 0.0;\n")
        f.write("\n")
        for i in range(0, self.outputGrid.NumberRows):
            if len(self.outputGrid.GetCellValue(i,0)) > 0:
                f.write("    strcpy(outputName["+str(i)+"], \""+str(self.outputGrid.GetCellValue(i,0))+"\");\n")
                if len(self.inputGrid.GetCellValue(i,1)) > 0:                
                    f.write("    outputValue["+str(i)+"] = "+str(self.outputGrid.GetCellValue(i,1))+";\n")                
                else:
                    f.write("    outputValue["+str(i)+"] = 0.0;\n")
        f.write("}\n")
        f.close()

# end of class MyFrame
if __name__ == "__main__":
    gettext.install("app") # replace with the appropriate catalog name

    app = wx.App()
    frame_1 = MyFrame(None, wx.ID_ANY, "")
    app.SetTopWindow(frame_1)
    frame_1.Show()
    frame_1.loadCFG()
    app.MainLoop()
