#!/bin/env python
#
# Automagically set the village_per_scout parameters in MP scenarios.

import sys
import os
import getopt
import re

overwrite = 0
defaultValue = 4
suffix = ''

RE_SCENARIO = '.*?\[multiplayer\].*?\[\/multiplayer\]'
scenario_block = re.compile(RE_SCENARIO, re.DOTALL)

RE_SIDE = re.compile('( |\t)*\[side\].*?\[\/side\]( |\t)*\n', re.DOTALL)
side_block = re.compile(RE_SIDE, re.DOTALL)

RE_AI = re.compile('( |\t)*\[ai\].*?\[\/ai\]( |\t)*\n', re.DOTALL)
ai_block = re.compile(RE_AI, re.DOTALL)

AI_SIDE = re.compile('(?P<text>( |\t)*side=(\w| |\-|\,|\t)*)\n', re.DOTALL)
AI_TIME = re.compile('(?P<text>( |\t)*time_of_day=(\w| |\-|\,|\t)*)', re.DOTALL)
AI_TURNS = re.compile('(?P<text>( |\t)*turns=(\w| |\-|\,|\t)*)', re.DOTALL)
AI_SCOUTS = re.compile('(?P<text>( |\t)*villages_per_scout=(\w| |\-|\,|\t)*)', re.DOTALL)
AI_SCOUTS_VALUE = re.compile('(?P<text>(?<=villages_per_scout=)(\d)*)', re.DOTALL)
AI_CAN_RECRUIT = re.compile('(?P<text>(?<=canrecruit=)(\d)*)', re.DOTALL)
AI_START = re.compile('(?P<text>( |\t)*\[ai\](\w| |\t)*\n)', re.DOTALL)

IF_TEXT = "[if]\n"
ENDIF_TEXT = "[/if]\n"
ELSE_TEXT = "[else]\n"
ENDELSE_TEXT = "[/else]"

SCOUTS_TEXT = "\n\tvillages_per_scout=0"
AI_SCOUTS_TEXT = "\n\t[ai]" + SCOUTS_TEXT.replace('\n','\n\t') + "\n\t[/ai]"

def applySearch(text, RE, groupId):
    data = RE.search(text, 0)
    if data <> None:
        return data.group(groupId)
    else:
        return ""

def updateDescription(ai,sides):
    if ai.value <> "":
        new = defaultValue*sides
        ai.updated_description = ai.updated_description.replace(ai.value,"%s"%(new))

def getIndent(itemText,subitemText):
    item = re.compile('^( |\t)*').search(itemText).group()
    subitem = re.compile('^( |\t)*').search(subitemText).group()
    if item == '' or subitem == '':
        return subitem
    if item[0] == '\t' and subitem[0] == '\t':
        return (len(subitem)-len(item)) * '\t'
    if item[0] == ' ' and subitem[0] == ' ':
        return (len(subitem)-len(item)) * ' '
    return '\t'
    
class wikiAi:
    def __init__(self):
        self.start = ""
        self.scouts = ""
        self.full_description = ""
        self.updated_description = ""

    def addAiData(self,aiContent):
        if aiContent <> None:
            self.start = applySearch(aiContent, AI_START, 'text')
            self.scouts = applySearch(aiContent, AI_SCOUTS, 'text')
            self.full_description = aiContent
            self.updated_description = aiContent
            self.value = applySearch(aiContent, AI_SCOUTS_VALUE, 'text')

class wikiAiList(list):
    def __str__(self):
        output = ""
        for item in self:
            output = output + item.full_description + " ; "
        return output

class wikiSide:
    def __init__(self):
        self.full_description = ''
        self.updated_description = ''
        self.side = ""
        # Will only contain one element
        self.ai = wikiAiList()
        self.scouts_setting = False

    def addAiData(self,sideContent):
        if sideContent <> None:
            aiDetail = ai_block.search(sideContent,0)
            while aiDetail <> None:
                if applySearch(aiDetail.group(), AI_TIME, 'text') == "":
                    if applySearch(aiDetail.group(), AI_TURNS, 'text') == "":
                        self.ai.append(wikiAi())
                        self.ai[self.getCurrentAiNumber()].addAiData(aiDetail.group())
                        if self.ai[self.getCurrentAiNumber()].scouts <> "":
                            self.scouts_setting = True
                        break
                searchStart = aiDetail.end()
                aiDetail = ai_block.search(sideContent,searchStart)
     

    def updateAi(self,sides):
        if len(self.ai) == 0:
            self.ai.append(wikiAi())
            space = re.compile('^( |\t)*').search(self.full_description).group()
            indent = getIndent(self.full_description,self.side)
            side_scout_text = AI_SCOUTS_TEXT.replace('\t',indent)
            side_scout_text = side_scout_text.replace('\n','\n' + space)
            self.ai[self.getCurrentAiNumber()].addAiData(side_scout_text)
            self.updated_description = self.updated_description.replace('\n',self.ai[self.getCurrentAiNumber()].full_description + '\n',1)
            updateDescription(self.ai[0],sides)
        else:
            if self.scouts_setting == False:
                space = re.compile('^( |\t)*').search(self.full_description).group()
                indent = getIndent(self.full_description,self.side)
                side_scout_text = AI_SCOUTS_TEXT.replace('\t',indent)
                side_scout_text = side_scout_text.replace('\n','\n' + space)
                self.ai[0].updated_description = self.ai[0].updated_description.replace(self.ai[0].start,self.ai[0].start.replace('\n',side_scout_text + '\n'))
                updateDescription(self.ai[0],sides)
            else:
                if overwrite == 1:
                    updateDescription(self.ai[0],sides)
        if self.ai[0].full_description <> self.ai[0].updated_description:
            self.updated_description = self.updated_description.replace(self.ai[0].full_description,self.ai[0].updated_description,1)
            
    def getCurrentAiNumber(self):
        return len(self.ai)-1

class wikiSideList(list):
    def __str__(self):
        output = ""
        for item in self:
            output = output + item.full_description + " ; "
        return output

class wikiScenario:
    def __init__(self):
        self.side = wikiSideList()
        self.full_description = ''
        self.updated_description = ''

    def parseScenario (self,scenarioContent):
        self.addScenarioData(scenarioContent)
        sideDetail = side_block.search(scenarioContent,0)
        while (sideDetail <> None):
            self.addSideData(sideDetail.group())
            self.addAiData(sideDetail.group())
            searchStart = sideDetail.end()
            sideDetail = side_block.search(scenarioContent,searchStart)
        self.updateAi()

    def addScenarioData(self, scenarioContent):
        self.full_description = scenarioContent
        self.updated_description = scenarioContent

    def addSideData(self, sideContent):
        canrecruit = applySearch(sideContent, AI_CAN_RECRUIT, 'text')
        if canrecruit <> "" and canrecruit == "0":
          return
        self.side.append(wikiSide())
        self.side[self.getCurrentSideNumber()].full_description = sideContent
        self.side[self.getCurrentSideNumber()].updated_description = sideContent
        self.side[self.getCurrentSideNumber()].side = applySearch(sideContent, AI_SIDE, 'text')

    def addAiData(self,aiContent):
        self.side[self.getCurrentSideNumber()].addAiData(aiContent)

    def updateAi(self):
        for side in self.side:
            side.updateAi(len(self.side))
        for side in self.side:
            if side.full_description <> side.updated_description:
                self.updated_description = self.updated_description.replace(side.full_description,side.updated_description,1)

    def getCurrentSideNumber(self):
        return len(self.side)-1

class wikiScenarioList(list):
    def __str__(self):
        output = ""
        for scenario in self:
            output = output + scenario.full_description + " ; "
        return output

    def addScenario(self, scenario):
        self.append(scenario)

def parseAll (resourcesFile,dirName, fileList):
    scenarioListIndex = 0
    scenarioList = wikiScenarioList()
    for fileName in fileList:
        if os.path.splitext(fileName)[1] <> '.cfg':
            continue
        if os.path.isdir(os.path.join(dirName,fileName)):
            continue
        f = file(os.path.join(dirName,fileName))
        fileContent = f.read()
        f.close()
        searchStart = 0
        scenario = scenario_block.match(fileContent,searchStart)
        while (scenario <>  None):
            scenarioList.addScenario(wikiScenario())
            scenarioList[scenarioListIndex].parseScenario(scenario.group(0))
            searchStart = scenario.end()
            scenario = scenario_block.search(fileContent,searchStart)
            scenarioListIndex = scenarioListIndex + 1
        updated_file = fileContent
        for scenarioItem in scenarioList:
            if scenarioItem.full_description <> scenarioItem.updated_description:
                updated_file = updated_file.replace(scenarioItem.full_description,scenarioItem.updated_description)
        if updated_file <> fileContent:
            (basename_out, ext_out) = os.path.splitext(fileName)
            basename_out = basename_out + suffix + ext_out
            f = file(basename_out,'w')
            f.write(updated_file)
            f.close

def printUsage():
    print "scoutDefault.py [-hRO] [-d directory] [-f file] [-x extension]"
    print "-h : print this message"
    print "-R : recursively parse directories"
    print "-O : overwrite village_per_scout value in scenario"
    print "-d : directory to look for file to parse"
    print "-f : name of the file to parse"
    print "-x : suffix to append to filename"
    print "Example of use:"
    print "  ./scoutDefault.py -h"
    print "    Get help"
    print "  ./scoutDefault.py -f 2p_Blitz.cfg -x _new"
    print "    Run the script and write output on 2p_Blitz_new.cfg"
    print "  ./scoutDefault.py -d /usr/local/share/wesnoth/data/scenarios"
    print "    Run the script on all file under that directory"
    print "  ./scoutDefault.py -R -d /usr/local/share/wesnoth"
    print "    Run the script on all directories under that directory"
    print "  ./scoutDefault.py -f 2p_Blitz.cfg -O"
    print "    Run the script on 2p_Blitz.cfg and delete previous value"

recursive = 0
entryPoint = os.getcwd()
entryFile = os.listdir(os.getcwd())
resourcesFile = {}
try:
    (opts, argsProper) = getopt.getopt(sys.argv[1:], 'ROhf:d:x:v:"')
except getopt.GetoptError, e:
    print 'Error parsing command-line arguments: %s' % e
    printUsage()
    sys.exit(1)
for (option, parameter) in opts:
    if option == '-h': # Print the commandline help and exit.
        printUsage()
        sys.exit(0)
    elif option == '-R':
        recursive = 1
    elif option == '-O':
        overwrite = 1
    elif option == '-d':
        if not os.path.exists(parameter):
            print 'Error: %s directory does not exist' % parameter
            sys.exit(1)
        elif not os.path.isdir(parameter):
            print 'Error: %s is not a directory' % parameter
            sys.exit(1)
        entryPoint = parameter
        entryFile = os.listdir(entryPoint)
    elif option == '-f':
        entryFile = []
        entryFile.append(os.path.basename(parameter))
        entryPoint = os.path.dirname(parameter)
    elif option == '-x':
        suffix = parameter

if recursive == 1:
    os.path.walk(entryPoint,parseAll,resourcesFile)
else:
    parseAll(resourcesFile,entryPoint,entryFile)
