###############################################################################
# File:        guCmdEditor.py
# Appointment: Interactive command editor (logic)
# Project:     GalaxyU
# Author:      AR
# Created:     25.01.2014
# Last change: 08.10.2016
###############################################################################
import wx, os

import zx
import wxTools
import guApp
import guCmdEditorFrame
import string
import webbrowser

from ctypes import *

#===============================================================================
# Interactive command editor
#===============================================================================
class CCmdEditor(guCmdEditorFrame.cmdEditorFrame):
    StaticEditor = None # static editor

    def __init__(self, parent):
        guCmdEditorFrame.cmdEditorFrame.__init__(self, parent)

        # Set size and position from cfg
        self.Cfg = zx.CCfgHolder(guApp.Application.Config, "GUI", "CCmdEditor")
        p = wxTools.LoadFramePosFromCfg(self.Cfg, self)
        self.SetPosition(p[0])
        self.SetSize(p[1])

        # Set control events
        self.buttonExit.Bind(wx.EVT_BUTTON, lambda e: self.Close())
        self.buttonLoad.Bind(wx.EVT_BUTTON, lambda e: self.__OnLoad(e))
        self.buttonSave.Bind(wx.EVT_BUTTON, lambda e: self.__Save())
        self.buttonRun.Bind(wx.EVT_BUTTON, lambda e: self.__OnRun())
        self.buttonMailTo.Bind(wx.EVT_BUTTON, lambda e: self.__OnMailTo())

        # Try to load existing order file
        self.FileName = os.path.splitext(guApp.Application.GetReport().FileName)[0] + ".ord"
        if os.path.isfile(self.FileName):
            self.textCtrl.LoadFile(self.FileName)
        else:
            # Add template text
            self.textCtrl.AppendText("#begin\n")
            self.textCtrl.AppendText("// *** ReportsViewer " + guApp.GetVersionStr() + " ***\n")
            self.textCtrl.AppendText("\n")
            self.textCtrl.AppendText(\
                "login " + guApp.Application.GetUserEmail() + \
                "/" + guApp.Application.GetUserPassword() + ";\n");
            self.textCtrl.AppendText("\n\n\n\n")
            self.textCtrl.AppendText("#end\n")
            
        self.SetTitle(self.FileName)

        # In Close event - save cfg 
        self.Bind(wx.EVT_CLOSE, self.__OnEventClose)
        

    #---------------------------------------------------------------------------
    def __OnClose(self, e):
        if self.__CheckForSave():
            self.Close()


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Loads file
    def __OnLoad(self, e):
        self.__CheckForSave()
        repDir = guApp.Application.Config.GetItem("Reports.Location")
        dlg = wx.FileDialog(self, message="Import Orders", defaultDir = repDir, wildcard = "*.ord", style = wx.OPEN)
        if os.path.isfile(self.FileName):
            dlg.SetFilename(self.FileName)
        if dlg.ShowModal() == wx.ID_OK:
            importFile = os.path.join(dlg.GetDirectory(), dlg.GetFilename())
            if importFile != self.FileName:
                self.textCtrl.LoadFile(importFile)
                self.textCtrl.SetModified(True) # force text be changed

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Saves data in file
    def __Save(self):
        if self.textCtrl.IsModified():
            self.textCtrl.SaveFile(self.FileName)
        
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Saves data if necessary. Returns True if window can be closed
    def __CheckForSave(self):
        if self.textCtrl.IsModified():
            res = wxTools.AskYesNo(self, "Would you like save changes?", "Saving order")
            if res == wx.ID_YES:
                self.__Save()
            elif res == wx.ID_CANCEL:
                return False
        return True


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    def __OnEventClose(self, e):
        if not self.__CheckForSave():
            e.Veto()
            return
        wxTools.SaveFramePosToCfg(self.Cfg, self)
        guApp.Application.WindowsCollection.Unregister(self)
        e.Skip()



    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    def __NormalizeCommandText(self):
        # Text correction against 'bad' copy&paste
        val = ""        
        for c in self.textCtrl.GetValue():
            if c in string.printable:
                val += c
            else:
                val += ' '
        if val != self.textCtrl.GetValue():
            self.textCtrl.ChangeValue(val);
            
        return str(self.textCtrl.GetValue())


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Executes commands from editor
    def __OnRun(self):
        # Save the order
        self.__Save()

        # Execute commands        
        translation = c_char_p("")
        commands = self.__NormalizeCommandText()
        guApp.Application.API.guExecuteCommands(\
            guApp.Application.GetReport().NationName, commands, byref(translation))
        self.textTrans.ChangeValue(translation.value)
        
        # Update report after the order executed
        guApp.Application.GetReport().Update()

        # Restore window
        self.textTrans.ShowPosition(self.textTrans.GetLastPosition()) # go to the end of translation
        self.Raise()

        # StarMap should be refresh first, because it triggers some coordinates normilizing
        wxTools.PublisherSendMessage(guApp.MESSAGE_REFRESH_STAR_MAP_DATA)
        # Now refresh all other data
        wxTools.PublisherSendMessage(guApp.MESSAGE_REFRESH_DATA)
        
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Sending email
    def __OnMailTo(self):
        SendTo(self.__NormalizeCommandText())

        
    #---------------------------------------------------------------------------
    # Returns a text position if #end to insert new lines before it
    def GetInsertPoint(self):
        pos = 0
        for row in range (0, self.textCtrl.GetNumberOfLines()):
            line = self.textCtrl.GetLineText(row)
            if line.strip() == "#end":
                return pos
            pos += len(line) + (2 if zx.IsWindows() else 1) # CR&LF

        return self.textCtrl.GetLastPosition()

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    # Removes the editor
    @staticmethod
    def Remove():
        # Remove existing editor
        if CCmdEditor.StaticEditor is not None:
            try:
                # Object may be deleted already
                CCmdEditor.StaticEditor.Close()
            except:
                # Ignore any exceptions here
                pass
            del CCmdEditor.StaticEditor
            CCmdEditor.StaticEditor = None

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    # Calls the editor
    @staticmethod
    def Call():
        if CCmdEditor.StaticEditor is None:
            CCmdEditor.StaticEditor = CCmdEditor(guApp.Application.GetMainWindow())

        try:
            # May fail if was closed explicitly
            CCmdEditor.StaticEditor.Show()
            CCmdEditor.StaticEditor.Raise()
            return CCmdEditor.StaticEditor
        except:
            # Explicitly remove and try again
            CCmdEditor.Remove()
            return CCmdEditor.Call()

#-------------------------------------------------------------------------------


#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# 'SendTo' text
def SendTo(aText):
    # As usual, windows needs special treatment
    lines = aText.split("\n")
    aText = ""
    for line in lines:
        aText += line + "%0D%0A" # this breaks lines

    webbrowser.open('mailto:galaxyservergm@gmail.com?subject=Galaxy Kings&body=' + aText, new=1)


#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Generates a text message to ruler
def GetTextMessageTo(aRuler, aSender = None):
    msgTxt = "#message\n"
    msgTxt += \
        "login: " + guApp.Application.GetUserEmail() + \
        "/" + guApp.Application.GetUserPassword() + "\n"
    msgTxt += "to: " + (\
        "All" if aRuler is None else (\
        "GM" if aRuler.NationName is None else aRuler.NationName))
    msgTxt += "\n\n"
    msgTxt += "Greetings, " + (\
        "All" if aRuler is None else (\
        "GM" if aRuler.NationName is None else \
        aRuler.Title + " " + aRuler.Name))

    msgTxt += "\n\n\n\n"

    if aSender is not None:
        msgTxt += "Kind Regards,\n"
        msgTxt += "GM" if aSender.NationName is None else aSender.Name
        msgTxt += "\n"

    msgTxt += "#end\n"

    return msgTxt

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Generates an email message to ruler
def SendMessageTo(aRuler, aSender):
    SendTo(GetTextMessageTo(aRuler, aSender))
