###############################################################################
# File:        guMain.py
# Appointment: main GUI module
# Project:     GalaxyU
# Author:      AR
# History:
# 31.01.2013 Report was moved in application
# 11.05.2012 Created
###############################################################################
import zx
import zxLog
import wxTools
import wxListLogTarget

import pgTools
import pgWxDisplay

import guApp
import guObjects
import guStarMap
import guShipCalc
import guShipsView
import guStarGen
import guFleetsView
import guBombingView
import guGBView
import guBattleListView
import guListView
import guLogTarget
import guStarsListView
import guTransportOrdersListView
import guProdOrdersListView
import guRatingListView
import guKnownNationsListView
import guReportMessagesListView
import guSciencesListView
import guMoneyTransactionsListView
import guAutoManagersListView
import guSpaceGroupsListView
import guCmdEditor
import guAbout

# Std modules
import getopt
import os
import pygame
import sys
import wx
from ctypes import *
from subprocess import call
from encodings import ascii

###############################################################################
# Main window
class Main(wxTools.CCfgFrame):
    ###########################################################################
    def __init__(self, parent):
        wxTools.CCfgFrame.__init__(self, parent, guApp.Application.Config, "GUI", "MainWindow")
        # GUI initialization
        self.InitUI()
 
    #--------------------------------------------------------------------------       
    def __OnSave(self):
        guApp.Application.CloseStarMap()
        guApp.Application.WindowsCollection.CloseAll()
    
    ###########################################################################
    def InitUI(self):    
        self.SetMinSize((700, 200))

        # Toolbar
        toolbar = self.CreateToolBar()

        # Build main menu
        menubar = wx.MenuBar()
        
        ## File menu
        menu = wx.Menu()

        ### Helper: adds menu item and a toolbar
        def AddMenuAndTool(aFunc, aText, aHelp, aIconPath, aMenu = None):
            parentMenu = menu if aMenu is None else aMenu
            mi = wx.MenuItem(parentMenu, wx.ID_ANY, aText, aHelp)
            origBm = wx.Bitmap(aIconPath)
            bm = wx.BitmapFromImage(\
                wx.ImageFromBitmap(origBm).Scale(24, 24, wx.IMAGE_QUALITY_HIGH))
            mi.SetBitmap(bm)
            bm = wx.BitmapFromImage(\
                wx.ImageFromBitmap(origBm).Scale(30, 30, wx.IMAGE_QUALITY_HIGH))
            self.Bind(wx.EVT_MENU, aFunc, parentMenu.AppendItem(mi))
            self.Bind(\
                wx.EVT_TOOL, aFunc,
                toolbar.AddLabelTool(\
                    wx.ID_ANY, '',
                    bm,
                    wx.NullBitmap, wx.ITEM_NORMAL,
                    aText, aHelp))
            
        AddMenuAndTool(\
            self.OnOpen, '&Open...', 'Open report',
            guApp.Application.ICONS_PATH + 'folder.png')
        
        menu.AppendSeparator()

        self.Bind(wx.EVT_MENU, self.OnQuit, menu.Append(wx.ID_EXIT, '&Quit', 'Quit application'))
        self.OnSaveCfg = self.__OnSave
        guApp.Application.SetMainWindow(self)

        menubar.Append(menu, '&File')
        
        ## Lists
        menu = wx.Menu()

        menubar.Append(menu, '&Lists')

        AddMenuAndTool(\
            lambda e: guReportMessagesListView.ShowReportMessagesList(),
            '&Report Messages', 'List of report messages',
            guApp.Application.ICONS_PATH + 'newspaper.png')
        toolbar.AddSeparator()

        menuStars = wx.Menu()
        AddMenuAndTool(\
            lambda e: guStarsListView.ShowYourColoniesList(),
            '&Your colonies', 'Your colonies',
            guApp.Application.ICONS_PATH + \
                'man-standing-on-planet-surface-with-a-flag-with-one-star.png', menuStars)

        AddMenuAndTool(\
            lambda e: guStarsListView.ShowUninhabitedSystemsList(),
            '&Uninhabited systems', 'Uninhabited systems',
            guApp.Application.ICONS_PATH + 'saturn-and-other-planets.png', menuStars)

        AddMenuAndTool(\
            lambda e: guStarsListView.ShowAlienColoniesList(),
            '&Alien colonies', 'Alien colonies',
            guApp.Application.ICONS_PATH + 'flag-on-planet-with-star-surrounded-by-stars.png', menuStars)

        AddMenuAndTool(\
            lambda e: guStarsListView.ShowKnownSystemsList(),
            '&Known star systems', 'Known star systems',
            guApp.Application.ICONS_PATH + 'planets-on-orbits.png', menuStars)

        AddMenuAndTool(\
            lambda e: guStarsListView.ShowNotInvestigatedSystemsList(),
            '&Not investigated star systems', 'Not investigated star systems',
            guApp.Application.ICONS_PATH + 'saturn-planet-shape.png', menuStars)

        AddMenuAndTool(\
            lambda e: guStarsListView.ShowStarsList(),
            'A&ll systems', 'All systems',
            guApp.Application.ICONS_PATH + 'stars-group.png', menuStars)

        menu.AppendMenu(wx.ID_ANY, '&Stars', menuStars)
        toolbar.AddSeparator()

        menuShips = wx.Menu()

        AddMenuAndTool(\
            lambda e: guShipsView.OwnShipsList(),
            '&Your ships', 'List of your ships',
            guApp.Application.ICONS_PATH + 'rocket-12.png', menuShips)

        AddMenuAndTool(\
            lambda e: guShipsView.OtherShipsList(),
            '&Other ships', 'List of other ships',
            guApp.Application.ICONS_PATH + 'rocket-turned-to-upper-right.png', menuShips)

        AddMenuAndTool(\
            lambda e: guShipsView.AllShipsList(),
            '&All ships', 'List of all ships',
            guApp.Application.ICONS_PATH + 'spaceship.png', menuShips)
        toolbar.AddSeparator()

        menu.AppendMenu(wx.ID_ANY, '&Ships', menuShips)

        AddMenuAndTool(\
            lambda e: \
                guApp.Application.WindowsCollection.RegisterAndShow(\
                    lambda: guListView.CListViewFrame(\
                        guApp.Application.GetMainWindow(),
                        lambda: guApp.Application.GetReport().ShipTypes,
                        lambda panel, listCreator: guShipsView.CShipTypesViewCtrl(panel, listCreator),
                        "CShipTypesViewFrame", "All ship types")),
            '&Ship Types', 'List of ship types',
            guApp.Application.ICONS_PATH + 'paper-airplane-toy.png')

        AddMenuAndTool(\
            lambda e: guFleetsView.FleetsList(\
                lambda: guApp.Application.GetReport().Fleets, "Fleets"),
            '&Fleets', 'List of fleets',
            guApp.Application.ICONS_PATH + 'spaceship-shape.png')
        toolbar.AddSeparator()

        menuSpaceGroups = wx.Menu()

        AddMenuAndTool(\
            lambda e: guSpaceGroupsListView.ShowOwnSpaceGroupsList(),
            '&Your Groups', 'List of your approaching groups',
            guApp.Application.ICONS_PATH + \
                'rocket-pointing-to-upper-left-direction.png', menuSpaceGroups)

        AddMenuAndTool(\
            lambda e: guSpaceGroupsListView.ShowApproachingSpaceGroupsList(),
            '&Approaching Groups', 'List of alien approaching groups',
            guApp.Application.ICONS_PATH + 'rounded-spacecraft.png', menuSpaceGroups)

        toolbar.AddSeparator()

        menu.AppendMenu(wx.ID_ANY, 'Space &Groups', menuSpaceGroups)

        AddMenuAndTool(\
            lambda e: guTransportOrdersListView.ShowTransportOrdersList(),
            '&Transport Orders', 'List of transport orders',
            guApp.Application.ICONS_PATH + 'delivery-van.png')

        AddMenuAndTool(\
            lambda e: guProdOrdersListView.ShowProdOrdersList('List of production orders', 0),
            '&Production Orders', 'All Production Orders',
            guApp.Application.ICONS_PATH + 'factory-building-1.png')

        toolbar.AddSeparator()

        AddMenuAndTool(\
            lambda e: guApp.Application.WindowsCollection.RegisterAndShow(\
                lambda: guListView.CListViewFrame(\
                    guApp.Application.GetMainWindow(),
                    lambda: guApp.Application.GetReport().GetBombRecords(0),
                    lambda panel, aListCreator: guBombingView.CBombViewCtrl(panel, aListCreator),
                    "CBombViewFrame", "All bombings")),
            '&Bombings', 'List of bombings',
            guApp.Application.ICONS_PATH + 'explosion.png')

        AddMenuAndTool(\
            lambda e: guGBView.ShowGroundBattles(0),
            '&Ground Battles', 'List of ground battles',
            guApp.Application.ICONS_PATH + 'space-arm.png')

        AddMenuAndTool(\
            lambda e: guBattleListView.ShowSpaceBattles(),
            '&Space Battles', 'List of space battles',
            guApp.Application.ICONS_PATH + 'crossed-swords.png')

        toolbar.AddSeparator()

        AddMenuAndTool(\
            lambda e: guRatingListView.ShowRatingList(),
            '&Nations Rating', 'List of nations rating',
            guApp.Application.ICONS_PATH + 'aquarius-astrological-sign.png')

        AddMenuAndTool(\
            lambda e: guKnownNationsListView.ShowKnownNationsList(),
            '&Known Nations', 'List of known nations',
            guApp.Application.ICONS_PATH + 'alien-face.png')

        AddMenuAndTool(\
            lambda e: guSciencesListView.ShowSciencesList(),
            '&Sciences', 'List of sciences',
            guApp.Application.ICONS_PATH + 'physics-atom.png')

        AddMenuAndTool(\
            lambda e: guMoneyTransactionsListView.ShowMoneyTransactionsList(),
            '&Money Transactions', 'List of budget spend/income',
            guApp.Application.ICONS_PATH + 'money-papers-of-dollars.png')

        AddMenuAndTool(\
            lambda e: guAutoManagersListView.ShowList(),
            '&Automated managers', 'List of automated managers',
            guApp.Application.ICONS_PATH + 'rack-servers.png')

        toolbar.AddSeparator()

        ## Tools
        menu = wx.Menu()
        self.__toolsMenu = menu
        menubar.Append(menu, '&Tools')

        AddMenuAndTool(\
            self.OnShipCalc,
            '&Ship designer', 'Ship designer',
            guApp.Application.ICONS_PATH + 'mathematical-calculator.png')

        AddMenuAndTool(\
            lambda e: guCmdEditor.CCmdEditor.Call(),
            '&Order Editor', 'Interactive Order Editor',
            guApp.Application.ICONS_PATH + 'edit-note.png')

        ## About
        menu = wx.Menu()
        menubar.Append(menu, '&Info')
        self.Bind(\
            wx.EVT_MENU,
            lambda e: self.__ShowAbout(),
            menu.Append(wx.ID_ANY, '&About', 'About'))
        
        self.SetMenuBar(menubar)
        
        # Create status bar
        self.Statusbar = self.CreateStatusBar()

        pygame.init()

        # Log list
        self.__logTarget = wxListLogTarget.CListLogTarget(self)
        guApp.Application.AddLogTarget(self.__logTarget)
        guApp.Application.Log(zxLog.LOG_INFO, "API Version=" + guApp.Application.API.guGetAPIVersion())
        gridSizer = wx.BoxSizer(wx.VERTICAL)
        gridSizer.Add(self.__logTarget, 1, wx.EXPAND | wx.ALL)
        self.__logTarget.SetFocus()
        self.SetSizer(gridSizer)
        guApp.Application.GetLog().Level = guApp.Application.Config.GetItem("Trace.TraceLevel");
        guApp.Application.Log(\
            zxLog.LOG_INFO, "Current Trace Level=" + str(guApp.Application.GetLog().Level))
        self.__logTarget.MaxNumberOfItems = \
            int(guApp.Application.Config.GetItem("Trace.MaxNumberOfItems", "10000"));
        guApp.Application.Log(\
            zxLog.LOG_INFO,
            "Max Number of displayed log items = " + str(self.__logTarget.MaxNumberOfItems))

        # Show toolbar
        toolbar.Realize()

        # Show main window
        self.SetTitle('GU Client')
        self.Show(True)

        # Load initial report
        if not self.__LoadReport():
            self.Close()


    #--------------------------------------------------------------------------
    def __ShowAbout(self):
        dlg = guAbout.DialogAbout(self)
        dlg.genButtonOk.Bind(wx.EVT_BUTTON, lambda event: dlg.Close())
        # <Product Version>.<Feature Version>.<BugFix Version>.<Build>
        dlg.staticTextGuiVersion.Label = guApp.GetVersionStr()
        dlg.staticTextApiVersion.Label = "API Version: " + guApp.Application.API.guGetAPIVersion()
        dlg.staticTextServerVersion.Label = "Server Version: " + guApp.Application.API.guGetServerVersion()
        dlg.ShowModal()
        dlg.Destroy()
        pass


    #--------------------------------------------------------------------------
    def __LoadReport(self):
        repDir = guApp.Application.Config.GetItem("Reports.Location")
        dlg = wx.FileDialog(\
            self, message="Open Report",
            defaultDir = repDir, wildcard = "*.rep;*.rar", style = wx.OPEN)
        dlg.SetFilename(guApp.Application.Config.GetItem("Reports.oldFileName"))
        res = False
        if dlg.ShowModal() == wx.ID_OK:
            guCmdEditor.CCmdEditor.Remove() # remove cmd editor if open
            
            guApp.Application.Config.SetItem(\
                "Reports.Location", c_char_p(dlg.GetDirectory())) # save in cfg
            guApp.Application.Config.SetItem(\
                "Reports.oldFileName", c_char_p(dlg.GetFilename())) # save in cfg
            filePath = os.path.join(dlg.GetDirectory(), dlg.GetFilename())
                
            if guApp.Application.GetReport().Load(c_char_p(filePath)):
                self.Statusbar.SetStatusText(\
                    guApp.Application.GetReport().NationName + \
                        "     (file: " + dlg.GetFilename() + ")")
                # Refresh map view
                self.__OnSave()
                guApp.Application.RefreshStarMap()
                report = guApp.Application.GetReport()
                # Show messages if there are some
                if len(report.ReportMessages) > 0:
                    guReportMessagesListView.ShowReportMessagesList()
                res = True

                # Customize Send Message menu
                #----------------------------

                title = "Send Message to"
                id = self.__toolsMenu.FindItem(title)
                if id != -1:
                    self.__toolsMenu.Delete(id)

                menuOptions = wx.Menu()

                # Helper: returns sender for report nation
                def GetReportSender():
                    if report.IsGM():
                        return guObjects.CRuler(None, "GM", "GM")
                    nr = zx.Find(report.NationsRating, lambda x: x.Nation == report.NationName)
                    if nr is None:
                        # This should never happen
                        wxTools.ErrorReport(None, "Failed to find nation " + report.NationName)
                        return guObjects.CRuler("", guObjects.NA, guObjects.NA)
                    return nr.GetRuler()
      
                # *All*
                self.Bind(\
                    wx.EVT_MENU, 
                    lambda e: \
                        guCmdEditor.SendMessageTo(None, GetReportSender()), 
                    menuOptions.Append(wx.ID_ANY, '&All', 'To all nations'))
      
                # GM
                if not report.IsGM():
                    self.Bind(\
                        wx.EVT_MENU, 
                        lambda e: \
                            guCmdEditor.SendMessageTo(\
                                guObjects.CRuler(None, "Henry", "Baron"), GetReportSender()),
                            menuOptions.Append(wx.ID_ANY, '&Game Master', 'To the Game Master'))

                # Add all available players
                self.__sendToMap = {}
                menuOptions.AppendSeparator()
                for nr in sorted(report.NationsRating, key = lambda nr: nr.Nation):
                    ruler = nr.GetRuler()
                    if ruler.Name != guObjects.NA and nr.Nation != report.NationName:
                        def menuActionFunc(event):
                            nn = self.__sendToMap[event.GetId()]
                            entry = zx.Find(report.NationsRating, lambda x: x.Nation == nn)
                            if entry is not None:
                                guCmdEditor.SendMessageTo(entry.GetRuler(), GetReportSender())
                            else:
                                # This should never happen
                                wxTools.ErrorReport(None, "Failed to find nation " + nn)
                        mi = wx.MenuItem(\
                            menuOptions, wx.NewId(), ruler.NationName, ruler.NationName,
                            wx.ITEM_NORMAL)
                        self.__sendToMap[mi.GetId()] = ruler.NationName
                        self.Bind(\
                            wx.EVT_MENU, 
                            lambda e: menuActionFunc(e),
                            menuOptions.AppendItem(mi))

                self.__toolsMenu.AppendMenu(wx.ID_ANY, title, menuOptions)
                
        dlg.Destroy()
        return res


    ###########################################################################
    # Menu events
    ###########################################################################


    ###########################################################################
    def OnOpen(self, e):
        self.__LoadReport()
        
    ###########################################################################
    def OnQuit(self, e):
        self.Close(force = True)

    ###########################################################################
    def OnShipCalc(self, e):
        guApp.Application.WindowsCollection.RegisterAndShow(\
            lambda: guShipCalc.CShipDesignerFrame(guApp.Application.GetMainWindow()))


###############################################################################
def main(argv):
    if len(argv) > 0:
        print argv
        if argv[0] == guStarGen.GENERATE_CMD_PARAM:
            if len(argv) != 2:
                print "ERROR: Report file name is absent"
                return

            guStarGen.Generate(argv[1])
            return

        print "ERROR: Invalid command line arguments", argv, \
                    ". Expected either none or '" + guStarGen.GENERATE_CMD_PARAM + "''"
        return

    # Add log targets:
    # std print
    guApp.Application.AddLogTarget(zxLog.CLogTarget())
    # gu (into a trace file)
    guApp.Application.AddLogTarget(guLogTarget.CLogTarget())

    Main(None)
    guApp.Application.wxApp.MainLoop()
    print "~~~~~~~~~~removing gApplication..."
    guApp.Application.Stop()


###############################################################################
if __name__ == '__main__':
    main(sys.argv[1:])


