// table to hold all settings for this wizard
PluginSettings <- {
    Type = 0 // cbToolPlugin

    Name = _T("")
    Title = _T("")
    Version = _T("")
    Description = _T("")
    Author = _T("")
    Email = _T("")
    Website = _T("")
    ThanksTo = _T("")

    HasConfig = false
    HasMenu = false
    HasModuleMenu = false
    HasToolbar = false
}
WxVersion <- 1; // 0 - wx 2.6, 1 - wx 2.8

// -----------------------------------------------------------------------------
// init wizard
function BeginWizard()
{
    local wiz_type = Wizard.GetWizardType();

    local intro_msg = _T("Welcome to the new Code::Blocks plugin wizard!\n" +
                         "This wizard will guide you to create a new Code::Blocks plugin.\n\n");
    if (PLATFORM == PLATFORM_MSW)
    {
        intro_msg += _T("\nVERY IMPORTANT NOTE:\n\n" +
                        "Code::Blocks is built with the GNU GCC compiler and links to\n" +
                        "the monolithic unicode wxWidgets DLL.\n" +
                        "This means that you must have exactly this setup to be able to\n" +
                        "build the generated plugin.\n" +
                        "You must also have defined two global variables:\n" +
                        "   1. $(#cb) pointing to Code::Blocks base dir (where CodeBlocks.cbp is)\n" +
                        "   2. $(#wx) pointing to wxWidgets base directory\n\n\n");
    }
    intro_msg += _T("When you 're ready to proceed, please click \"Next\"...");

    Wizard.AddInfoPage(_T("PluginIntro"), intro_msg);
    Wizard.AddProjectPathPage();
    Wizard.AddPage(_T("PluginOptions"));
    Wizard.AddPage(_T("PluginInfo"));
    Wizard.AddGenericSingleChoiceListPage(_T("wxVersionPage"), _T("Please select the wxWidgets version you want to use."), _T("wxWidgets 2.6.x;wxWidgets 2.8.x"), WxVersion); // select wxwidgets version
    Wizard.AddCompilerPage(_T(""), _T("gcc*"), true, false);
}

// -----------------------------------------------------------------------------
// entering plugin options page
function OnEnter_PluginOptions(fwd)
{
    // update options state
    OnClick_cmbPluginType();
}

// -----------------------------------------------------------------------------
// enable/disable available options based on selected plugin type
function OnClick_cmbPluginType()
{
    PluginSettings.Type = Wizard.GetComboboxSelection(_T("cmbPluginType"));

    local isTool = PluginSettings.Type == 1;
    local isMime = PluginSettings.Type == 2;
    local isWizard = PluginSettings.Type == 3;
    Wizard.EnableWindow(_T("chkHasConfig"), !isWizard);
    Wizard.EnableWindow(_T("chkHasMenu"), !isTool && !isMime && !isWizard);
    Wizard.EnableWindow(_T("chkHasModuleMenu"), !isTool && !isMime && !isWizard);
    Wizard.EnableWindow(_T("chkHasToolbar"), !isTool && !isMime && !isWizard);
}

// -----------------------------------------------------------------------------
// leaving plugin options page, validate entered values
function OnLeave_PluginOptions(fwd)
{
    if (fwd)
    {
        // read text values entered
        PluginSettings.Name = Wizard.GetTextControlValue(_T("txtPluginName"));
        PluginSettings.Type = Wizard.GetComboboxSelection(_T("cmbPluginType"));
        PluginSettings.HasConfig = Wizard.IsCheckboxChecked(_T("chkHasConfig"));
        PluginSettings.HasMenu = Wizard.IsCheckboxChecked(_T("chkHasMenu"));
        PluginSettings.HasModuleMenu = Wizard.IsCheckboxChecked(_T("chkHasModuleMenu"));
        PluginSettings.HasToolbar = Wizard.IsCheckboxChecked(_T("chkHasToolbar"));

        // check that essentials were filled in
        if (PluginSettings.Name.IsEmpty())
        {
            ShowWarning(_T("You have to enter the plugin's name before you can proceed..."));
            return false;
        }
    }
    return true;
}

// -----------------------------------------------------------------------------
// entering plugin info page, set some default values
function OnEnter_PluginInfo(fwd)
{
    if (fwd)
    {
        // set the title same as the project title
        if (Wizard.GetTextControlValue(_T("txtTitle")).IsEmpty())
            Wizard.SetTextControlValue(_T("txtTitle"), Wizard.GetProjectTitle());
        if (Wizard.GetTextControlValue(_T("txtVersion")).IsEmpty())
            Wizard.SetTextControlValue(_T("txtVersion"), _T("0.1"));

        // load config
        Wizard.SetTextControlValue(_T("txtAuthor"), GetConfigManager().Read(_T("/cb_plugin_wizard/author"), _T("")));
        Wizard.SetTextControlValue(_T("txtEmail"), GetConfigManager().Read(_T("/cb_plugin_wizard/email"), _T("")));
        Wizard.SetTextControlValue(_T("txtWebsite"), GetConfigManager().Read(_T("/cb_plugin_wizard/website"), _T("")));
    }
}

// -----------------------------------------------------------------------------
// leaving plugin info page, validate entered values
function OnLeave_PluginInfo(fwd)
{
    if (fwd)
    {
        // read text values entered
        PluginSettings.Title = Wizard.GetTextControlValue(_T("txtTitle"));
        PluginSettings.Version = Wizard.GetTextControlValue(_T("txtVersion"));
        PluginSettings.Description = Wizard.GetTextControlValue(_T("txtDescription"));
        PluginSettings.Author = Wizard.GetTextControlValue(_T("txtAuthor"));
        PluginSettings.Email = Wizard.GetTextControlValue(_T("txtEmail"));
        PluginSettings.Website = Wizard.GetTextControlValue(_T("txtWebsite"));
        PluginSettings.ThanksTo = Wizard.GetTextControlValue(_T("txtThanksTo"));

        // check that essentials were filled in
        if (PluginSettings.Name.IsEmpty() ||
            PluginSettings.Version.IsEmpty())
        {
            ShowWarning(_T("You have to fill the Title and Version fields before you can proceed..."));
            return false;
        }
        PluginSettings.Name = GetFixedProjectName(PluginSettings.Name);
    }

    // save config
    GetConfigManager().Write(_T("/cb_plugin_wizard/author"), PluginSettings.Author);
    GetConfigManager().Write(_T("/cb_plugin_wizard/email"), PluginSettings.Email);
    GetConfigManager().Write(_T("/cb_plugin_wizard/website"), PluginSettings.Website);
    return true;
}

////////////////////////////////////////////////////////////////////////////////
// wxWidgets' version page
////////////////////////////////////////////////////////////////////////////////

function OnEnter_wxVersionPage(fwd)
{
    if (fwd)
    {
        WxVersion = Wizard.GetListboxSelection(_T("GenericChoiceList"));
    }
    return true;
}

function OnLeave_wxVersionPage(fwd)
{
    if (fwd)
    {
        WxVersion = Wizard.GetListboxSelection(_T("GenericChoiceList"));
    }
    return true;
}

// -----------------------------------------------------------------------------
// each time, return a string of the form "filename.ext;contents"
// you can change the return string based on <file_index>
// return an empty string to denote that no more files are to be generated
function GetGeneratedFile(file_index)
{
    switch (file_index)
    {
        // header file
        case 0: return PluginSettings.Name + DOT_EXT_H + _T(";") + GenerateHeader();
        // source file
        case 1: return PluginSettings.Name + DOT_EXT_CPP + _T(";") + GenerateSource();
        // manifest
        case 2: return _T("manifest") + DOT_EXT_XML + _T(";") + GenerateManifest();
    }
    return _T(""); // no more generated files
}

// -----------------------------------------------------------------------------
// setup the project options
function SetupProject(project)
{
    local target = project.GetBuildTarget(_T("default"));
    if (IsNull(target))
        target = project.AddBuildTarget(_T("default"));
    SetupTarget(target, true);

    return true;
}

function SetupTarget(target,is_debug)
{
    if (IsNull(target))
        return false;

    target.SetTargetType(ttDynamicLib);
    target.SetOutputFilename(PluginSettings.Name);
    target.SetCreateDefFile(false);
    target.SetCreateStaticLib(false);

    if (PLATFORM == PLATFORM_MSW)
    {
        target.AddCompilerOption(_T("-DBUILDING_PLUGIN"));
        target.AddCompilerOption(_T("-DHAVE_W32API_H"));
        target.AddCompilerOption(_T("-D__WXMSW__"));
        target.AddCompilerOption(_T("-DWXUSINGDLL"));
        target.AddCompilerOption(_T("-DcbDEBUG"));
        target.AddCompilerOption(_T("-DCB_PRECOMP"));
        target.AddCompilerOption(_T("-DWX_PRECOMP"));
        target.AddCompilerOption(_T("-DwxUSE_UNICODE"));
        target.AddCompilerOption(_T("-pipe"));
        target.AddCompilerOption(_T("-mthreads"));
        target.AddCompilerOption(_T("-fmessage-length=0"));
        target.AddCompilerOption(_T("-fexceptions"));
        target.AddCompilerOption(_T("-Winvalid-pch"));

        target.AddLinkerOption(_T("-mthreads"));

        target.AddIncludeDir(_T("$(#cb)\\include"));
        target.AddIncludeDir(_T("$(#cb)\\sdk\\wxscintilla\\include"));
        target.AddIncludeDir(_T("$(#wx.include)"));
        target.AddIncludeDir(_T("$(#wx.lib)\\gcc_dll\\mswu"));

        target.AddLinkLib(_T("codeblocks"));
        if (WxVersion == 0)
            target.AddLinkLib(_T("wxmsw26u"));
        else
            target.AddLinkLib(_T("wxmsw28u"));

        target.AddLibDir(_T("$(#cb)\\devel"));
        target.AddLibDir(_T("$(#wx.lib)\\gcc_dll"));

        target.SetHostApplication(_T("$(#cb)\\devel\\codeblocks") + DOT_EXT_EXECUTABLE);
    }
    else
    {
        target.AddCompilerOption(_T("`pkg-config --cflags codeblocks`"));
        target.AddCompilerOption(_T("`wx-config --cflags`"));
        target.AddCompilerOption(_T("-ansi"));
        target.AddCompilerOption(_T("-fPIC"));

        target.AddLinkerOption(_T("`pkg-config --libs codeblocks`"));
        target.AddLinkerOption(_T("`wx-config --libs`"));

        target.SetHostApplication(_T("codeblocks") + DOT_EXT_EXECUTABLE);
    }

    // create plugin resources
    target.AddCommandsAfterBuild(_T("zip -j9 ") +
                                PluginSettings.Name + _T(".zip manifest") + DOT_EXT_XML);
    // create plugin distribution file
    target.AddCommandsAfterBuild(_T("zip -j9 ") + PluginSettings.Name + _T(".cbplugin ") +
                                target.GetOutputFilename() + _T(" ") +
                                PluginSettings.Name + _T(".zip"));

    if (is_debug)
        DebugSymbolsOn(target, Wizard.GetCompilerID());

    return true;
}



////////////////////////////////////////////////////////////////////////////////
//
// locally defined functions below
//
////////////////////////////////////////////////////////////////////////////////



// -----------------------------------------------------------------------------
// return the header contents string
function GenerateHeader()
{
    local path = Wizard.FindTemplateFile(GetTemplateFile(DOT_EXT_H));
    local buffer = IO.ReadFileContents(path);

    // create header guard word
    local guard = PluginSettings.Name + DOT_EXT_H + _T("_INCLUDED");
    guard.MakeUpper();
    guard.Replace(_T(" "), _T("_"));
    guard.Replace(_T("."), _T("_"));
    buffer.Replace(_T("[GUARD_WORD]"), guard);

    return SubstituteMacros(buffer);
}

// -----------------------------------------------------------------------------
// return the implementation contents string
function GenerateSource()
{
    local path = Wizard.FindTemplateFile(GetTemplateFile(DOT_EXT_CPP));
    local buffer = IO.ReadFileContents(path);

    return SubstituteMacros(buffer);
}

// -----------------------------------------------------------------------------
// return the manifest contents string
function GenerateManifest()
{
    local path = Wizard.FindTemplateFile(_T("plugins/templates/manifest_template.xml"));
    local buffer = IO.ReadFileContents(path);

    return SubstituteMacros(buffer);
}

// -----------------------------------------------------------------------------
// return the template's filename, appending <dot_ext> as an extension (must include the dot)
function GetTemplateFile(dot_ext)
{
    local template_file = _T("");
    switch (PluginSettings.Type)
    {
        // generic plugin
        case 0: template_file = _T("plugins/templates/generic_template") + dot_ext; break;
        // tool plugin
        case 1: template_file = _T("plugins/templates/tool_template") + dot_ext; break;
        // mime plugin
        case 2: template_file = _T("plugins/templates/mime_template") + dot_ext; break;
        // wizard plugin
        case 3: template_file = _T("plugins/templates/wizard_template") + dot_ext; break;

        default: break; // error
    }
    return template_file;
}

// -----------------------------------------------------------------------------
// substitute all plugin macros in <buffer>
function SubstituteMacros(buffer)
{
    // handle [IF] / [ENDIF] pairs
    buffer = HandleDirective(buffer, _T("HAS_CONFIGURE"), PluginSettings.HasConfig);
    buffer = HandleDirective(buffer, _T("HAS_MENU"), PluginSettings.HasMenu);
    buffer = HandleDirective(buffer, _T("HAS_MODULE_MENU"), PluginSettings.HasModuleMenu);
    buffer = HandleDirective(buffer, _T("HAS_TOOLBAR"), PluginSettings.HasToolbar);
    buffer = HandleDirective(buffer, _T("NEED_EVENTS"), PluginSettings.HasMenu ||
                                                        PluginSettings.HasModuleMenu ||
                                                        PluginSettings.HasToolbar);

    // macros substitution
    buffer.Replace(_T("[PLUGIN_SDK_VERSION_MAJOR]"), _T("") + PLUGIN_SDK_VERSION_MAJOR);
    buffer.Replace(_T("[PLUGIN_SDK_VERSION_MINOR]"), _T("") + PLUGIN_SDK_VERSION_MINOR);
    buffer.Replace(_T("[PLUGIN_SDK_VERSION_RELEASE]"), _T("") + PLUGIN_SDK_VERSION_RELEASE);
    buffer.Replace(_T("[PLUGIN_NAME]"), PluginSettings.Name);
    buffer.Replace(_T("[PLUGIN_TITLE]"), PluginSettings.Title);
    buffer.Replace(_T("[PLUGIN_VERSION]"), PluginSettings.Version);
    buffer.Replace(_T("[PLUGIN_DESCRIPTION]"), PluginSettings.Description);
    buffer.Replace(_T("[PROJECT_NAME]"), Wizard.GetProjectName());
    buffer.Replace(_T("[AUTHOR_NAME]"), PluginSettings.Author);
    buffer.Replace(_T("[AUTHOR_EMAIL]"), PluginSettings.Email);
    buffer.Replace(_T("[AUTHOR_WWW]"), PluginSettings.Website);
    buffer.Replace(_T("[THANKS_TO]"), PluginSettings.ThanksTo);
    buffer.Replace(_T("[HEADER_FILENAME]"), PluginSettings.Name + DOT_EXT_H);
    buffer.Replace(_T("[NOW]"), ReplaceMacros(_T("$(TODAY)"), false));

    return buffer;
}

// -----------------------------------------------------------------------------
// if <enabled> is true, removes the [IF <directive>] and [ENDIF <directive>]
// macros.
// if <enabled> is false, removes everything enclosed by the [IF <directive>]
// and [ENDIF <directive>] macros (including them).
function HandleDirective(buffer, directive, enabled)
{
    local dir_if = _T("[IF ") + directive + _T("]");
    local dir_endif = _T("[ENDIF ") + directive + _T("]");

    local findStart = buffer.Find(dir_if);
    if (findStart == -1)
        return buffer;

    local findEnd = buffer.Find(dir_endif);
    if (findEnd == -1 || findEnd <= findStart)
        return buffer;

    // look for [ELSE]
    local block = buffer.Mid(findStart, findEnd - findStart);
    local findElse = block.Find(_T("[ELSE]")); // findElse is in "local scope", i.e. offset from findStart

    if (!enabled)
    {
        if (findElse == -1)
        {
            // remove whole section
            buffer.Remove(findStart, (findEnd - findStart) + dir_endif.Length());
        }
        else
        {
            // remove [ENDIF]
            buffer.Remove(findEnd, dir_endif.Length());
            // remove from [IF] to [ELSE] (including)
            buffer.Remove(findStart, findElse + 6); // 6 is the [ELSE] size
        }
    }
    else
    {
        if (findElse == -1)
        {
            // just remove the directives
            // we must remove the [ENDIF] first because if we removed the [IF] it would
            // render the findEnd index invalid!
            buffer.Remove(findEnd, dir_endif.Length());
            buffer.Remove(findStart, dir_if.Length());
        }
        else
        {
            // remove from [ELSE] to [ENDIF]
            local start = findStart + findElse;
            buffer.Remove(start, (findEnd - start) + dir_endif.Length());
            // remove from [IF]
            buffer.Remove(findStart, dir_if.Length());
        }
    }

    return buffer;
}
