//==============================================================================
//	Base class for tab panels which access playinfo information
//
//	Created by Ron Prestenback
//	© 2003, Epic Games, Inc.  All Rights Reserved
//==============================================================================
class UT2K4PlayInfoPanel extends UT2K4TabPanel
	abstract;

var() int                               NumColumns;
var array<PlayInfo.PlayInfoData>        InfoRules;
var automated	GUIMultiOptionListBox   lb_Rules;
var				GUIMultiOptionList      li_Rules;
var() config bool                       bVerticalLayout;
var() editconst noexport PlayInfo       GamePI;
var() noexport bool                     bRefresh, bUpdate;
var() localized string                  EditText;

function InitComponent(GUIController MyC, GUIComponent MyO)
{
	lb_Rules.NumColumns = NumColumns;
	Super.InitComponent(MyC, MyO);

	li_Rules = lb_Rules.List;
	li_Rules.OnCreateComponent = InternalOnCreateComponent;
    li_Rules.bHotTrack = True;
}

function bool CanShowPanel()
{
	if (GamePI == None)
		return false;

	return Super.CanShowPanel();
}

// Called from the owning page when GameType has been changed or PlayInfo settings have been reloaded
function Refresh()
{
	GamePI.GetSettings(MyButton.Caption, InfoRules);
	ClearRules();
	LoadRules();
}

// This function is used to initialize the GUIMultiOptionList with the settings in PlayInfo
function LoadRules()
{
	if (bUpdate)
		UpdateRules();
}

// This function updates the values of the menu options of the GUIMultiOptionList
// with the correct values from PlayInfo
function UpdateRules()
{
	local int i, j;

    for (i = 0; i < li_Rules.Elements.Length; i++)
    {
        if ( GUIListSpacer(li_Rules.Elements[i]) != None )
            continue;

        j = li_Rules.Elements[i].Tag;

        // The index got corrupted - dump the contents of the our list to see what's going on
        // then crash the game to get our attention :>
        if (InfoRules[j].DisplayName != li_Rules.Elements[i].Caption)
            DumplistElements(i, j);

        Assert(InfoRules[j].DisplayName == li_Rules.Elements[i].Caption);

        li_Rules.Elements[i].SetHint(InfoRules[j].Description);

    // Update the value of the GUIMenuOption with the actual value in PlayInfo
        if (j < InfoRules.Length)
        	li_Rules.Elements[i].SetComponentValue(InfoRules[j].Value, True);

        // Assign the TabOrder so that user can tab properly between list elements
        li_Rules.Elements[i].TabOrder = i;
    }

	bRefresh = False;
	bUpdate = False;
}

function DumpListElements(int BadListIndex, int BadPlayInfoIndex)
{
    local int i;

    log("** DumpListElements **");
    log("Element["$BadListIndex$"] caption:"$li_Rules.Elements[BadListIndex].Caption@"Setting["$BadPlayInfoIndex$"] caption:"$GamePI.Settings[BadPlayInfoIndex].DisplayName);
    for (i = 0; i < li_Rules.Elements.Length; i++)
    {
        log(i$")"@li_Rules.Elements[i].Caption@li_Rules.Elements[i].Tag);
    }

    GamePI.Dump();
}

// Whoa ...
// Add a new rule to the GUIMultiOptionList
function AddRule(PlayInfo.PlayInfoData NewRule, int Index)
{
    local bool bTemp;
    local string        Width, Op;
    local array<string> Range;
    local moComboBox    co;
    local moFloatEdit   fl;
    local moEditBox     ed;
    local moCheckbox    ch;
    local moNumericEdit nu;
    local moButton      bu;
    local int           i, pos;

    bTemp = Controller.bCurMenuInitialized;
    Controller.bCurMenuInitialized = False;

    switch (NewRule.RenderType)
    {
        case PIT_Check:
            ch = moCheckbox(li_Rules.AddItem("XInterface.moCheckbox",,NewRule.DisplayName, True));
            if (ch == None)
                break;

            ch.Tag = Index;
            ch.bAutoSizeCaption = True;
            break;

        case PIT_Select:
            co = moCombobox(li_Rules.AddItem("XInterface.moComboBox",,NewRule.DisplayName, True));
            if (co == None)
                break;

            co.ReadOnly(True);
            co.bAutoSizeCaption = True;
            co.Tag = Index;
            co.CaptionWidth=0.5;
            GamePI.SplitStringToArray(Range, NewRule.Data, ";");
            for (i = 0; i+1 < Range.Length; i += 2)
                co.AddItem(Range[i+1],,Range[i]);

            break;

        case PIT_Text:
        	if ( !Divide(NewRule.Data, ";", Width, Op) )
        		Width = NewRule.Data;

            pos = InStr(Width, ",");
            if (pos != -1)
                Width = Left(Width, pos);

            if (Width != "")
                i = int(Width);
            else i = -1;
            GamePI.SplitStringToArray(Range, Op, ":");
            if (Range.Length > 1)
            {
                // Ranged data
                if (InStr(Range[0], ".") != -1)
                {
                    // float edit
                    fl = moFloatEdit(li_Rules.AddItem("XInterface.moFloatEdit",,NewRule.DisplayName, True));
                    if (fl == None) break;
                    fl.Tag = Index;
                    fl.bAutoSizeCaption = True;
                    fl.ComponentWidth = 0.25;
                    if (i != -1)
                        fl.Setup( float(Range[0]), float(Range[1]), fl.MyNumericEdit.Step);
                }

                else
                {
                    nu = moNumericEdit(li_Rules.AddItem("XInterface.moNumericEdit",,NewRule.DisplayName, True));
                    if (nu == None) break;
                    nu.Tag = Index;
                    nu.bAutoSizeCaption = True;
                    nu.ComponentWidth = 0.25;
                    if (i != -1)
                        nu.Setup( int(Range[0]), int(Range[1]), nu.MyNumericEdit.Step);
                }
            }
            else if (NewRule.ArrayDim != -1)
            {
                bu = moButton(li_Rules.AddItem("XInterface.moButton",,NewRule.DisplayName, True));
                if (bu == None) break;
                bu.Tag = Index;
                bu.bAutoSizeCaption = True;
                bu.ComponentWidth = 0.25;
                bu.OnChange = ArrayPropClicked;
            }

            else
            {
                ed = moEditbox(li_Rules.AddItem("XInterface.moEditBox",,NewRule.DisplayName, True));
                if (ed == None) break;
                ed.Tag = Index;
                ed.bAutoSizeCaption = True;
                if (i != -1)
                    ed.MyEditBox.MaxWidth = i;
            }
            break;

        default:
            bu = moButton(li_Rules.AddItem("XInterface.moButton",,NewRule.DisplayName, True));
            if (bu == None) break;
            bu.Tag = Index;
            bu.bAutoSizeCaption = True;
            bu.StandardHeight = 0.03;
            bu.ComponentWidth = 0.25;
            bu.OnChange = CustomClicked;
    }

    Controller.bCurMenuInitialized = bTemp;
}

function AddGroupHeader(int PlayInfoIndex, bool InitialRow)
{
    local int ModResult, i;
    local GUIMenuOption mo;

    //  If the GUIMultiOptionList has more than one column, add a spacer component
    //  for each column until we are back to the first column
    if ( !li_Rules.bVerticalLayout )
    {
	    ModResult = li_Rules.Elements.Length % lb_Rules.NumColumns;
	    while (ModResult-- > 0)
	        li_Rules.AddItem( "XInterface.GUIListSpacer" );

	    if (!InitialRow)
	        for (i = 0; i < lb_Rules.NumColumns; i++)
	            li_Rules.AddItem( "XInterface.GUIListSpacer" );
	}

    // We are now at the first column - safe to add a header row
    mo = li_Rules.AddItem( "XInterface.GUIListHeader",, InfoRules[PlayInfoIndex].Grouping );
    if ( mo != None )
    	mo.bAutoSizeCaption = True;

	if ( !li_Rules.bVerticalLayout )
	{
	    i = 0;
	    while (++i < lb_Rules.NumColumns)
	    {
		    mo = li_Rules.AddItem( "XInterface.GUIListHeader" );
		    if ( mo != None )
		    	mo.bAutoSizeCaption = True;
		}
	}
}

function ClearRules()
{
	li_Rules.Clear();
}

function InternalOnActivate()
{
	if (bRefresh)
		Refresh();
	else if (bUpdate)
		UpdateRules();
}

function ListBoxCreateComponent(GUIComponent NewComp, GUIComponent Sender)
{
    if (GUIMultiOptionList(NewComp) != None)
    {
    	GUIMultiOptionList(NewComp).bVerticalLayout = bVerticalLayout;
        GUIMultiOptionList(NewComp).bDrawSelectionBorder = False;
        GUIMultiOptionList(NewComp).ItemPadding = 0.15;
    }

    if (Sender == lb_Rules)
        lb_Rules.InternalOnCreateComponent(NewComp, Sender);
}

function InternalOnCreateComponent(GUIMenuOption NewComp, GUIMultiOptionList Sender)
{
	if (Sender == li_Rules)
	{
		NewComp.ComponentJustification = TXTA_Right;
		NewComp.LabelJustification = TXTA_Left;
	    NewComp.CaptionWidth = 0.65;

	    if (moButton(NewComp) != None)
	    {
	        moButton(NewComp).ButtonStyleName = "SquareButton";
	        moButton(NewComp).ButtonCaption = EditText;
	    }
	}
}

function InternalOnChange(GUIComponent Sender)
{
	if (GUIMultiOptionList(Sender) != None)
	{
		if (Controller.bCurMenuInitialized)
			UpdateSetting(GUIMultiOptionList(Sender).Get());
	}

	else if ( GUIMenuOption(Sender) != None && Controller.bCurMenuInitialized )
		UpdateSetting( GUIMenuOption(Sender) );
}

function UpdateSetting(GUIMenuOption Sender)
{
    local int i;
    local int Index;

    if (Sender == None)
        return;

    i = Sender.Tag;
    if (i < 0)
        return;

    if (InfoRules[i].DisplayName != Sender.Caption)
    {
    	if ( Controller.bModAuthor )
		{
		   	log("Corrupt list index detected in component"@Sender.Name,'ModAuthor');
    		DumpListElements( FindComponentIndex(Sender), i );
    	}
    	return;
    }

    Index = GamePI.FindIndex(InfoRules[i].SettingName);
    if (InfoRules[i].DisplayName != Sender.Caption || Index == -1)
    {
    	if ( Controller.bModAuthor )
    	{
	    	log("Invalid setting requested from PlayInfo!",'ModAuthor');
	    	DumpListElements(FindComponentIndex(Sender), i);
	    }
    	return;
    }

    StoreSetting(Index, Sender.GetComponentValue());
}

protected function StoreSetting( int Index, string NewValue )
{
	GamePI.StoreSetting(Index, NewValue);
}

function ArrayPropClicked(GUIComponent Sender)
{
    local int i, Index;
    local GUIArrayPropPage ArrayPage;
    local string ArrayMenu;

    i = Sender.Tag;
    if (i < 0)
        return;

    Index = GamePI.FindIndex(InfoRules[i].SettingName);
	if ( GamePI.Settings[Index].ArrayDim > 1 )
		ArrayMenu = Controller.ArrayPropertyMenu;
	else ArrayMenu = Controller.DynArrayPropertyMenu;

    if (Controller.OpenMenu(ArrayMenu, GamePI.Settings[Index].DisplayName, GamePI.Settings[Index].Value))
    {
        ArrayPage = GUIArrayPropPage(Controller.ActivePage);
        ArrayPage.Item = GamePI.Settings[Index];
        ArrayPage.OnClose = CustomPageClosed;
        ArrayPage.SetOwner(Sender);
    }
}

function CustomClicked(GUIComponent Sender)
{
	local int i, Index;
	local GUICustomPropertyPage Page;
	local string CustomMenu;
	local array<string> Parts;

	i = Sender.Tag;
	if ( i < 0 )
		return;

	Index = GamePI.FindIndex( InfoRules[i].SettingName );
	Split(GamePI.Settings[Index].Data, ";", Parts);
	if ( Parts.Length > 2 )
	{
		CustomMenu = Parts[2];
		if ( Controller.OpenMenu(CustomMenu) )
		{
			Page = GUICustomPropertyPage(Controller.ActivePage);
			Page.Item = GamePI.Settings[Index];
			Page.OnClose = CustomPageClosed;
			Page.SetOwner(Sender);
		}
	}
}

function CustomPageClosed( optional bool bCancelled )
{
	local GUICustomPropertyPage Page;
	local GUIComponent CompOwner;

	Page = GUICustomPropertyPage(Controller.ActivePage);
	if ( Page != None && !bCancelled )
	{
		CompOwner = Page.GetOwner();
		if ( CompOwner != None && moButton(CompOwner) != None )
		{
			moButton(CompOwner).SetComponentValue( Page.GetDataString(), True );
			InternalOnChange(CompOwner);
		}
	}
}

function int FindComponentWithTag(int FindTag)
{
	local int i;

	for ( i = 0; i < li_Rules.Elements.Length; i++ )
	{
		if ( li_Rules.Elements[i].Tag == FindTag )
			return i;
	}

	return -1;
}

function int FindGroupIndex(string Group)
{
    local int i;

    for (i = 0; i < GamePI.Groups.Length; i++)
        if (GamePI.Groups[i] ~= Group)
            return i;

    return -1;
}

function Free()
{
	GamePI = None;
	Super.Free();
}

DefaultProperties
{
    EditText="Edit"
	NumColumns=1
	OnActivate=InternalOnActivate
	bRefresh=True
	bUpdate=False
    FadeInTime=0.25

    Begin Object Class=GUIMultiOptionListBox Name=RuleListBox
        OnChange=InternalOnChange
        OnCreateComponent=ListBoxCreateComponent
        bBoundToParent=True
        bScaleToParent=True
        WinWidth=1.000000
        WinHeight=0.930009
        WinLeft=0.000000
        WinTop=0.000000
        TabOrder=0
        bVisibleWhenEmpty=True
    End Object
    lb_Rules=RuleListBox
}
