//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop

#include "CharacterClass.h"
#include "CharacterUnit.h"
#include "SDIMain.h"
#include "ItemUnit.h"
#include <inifiles.hpp>
//---------------------------------------------------------------------------
#pragma resource "*.dfm"

#define MAX_MINDSETS 100

TCharacterForm *CharacterForm;
extern CharacterNode CharListHead;
CharacterNode cnCurrent;
InventoryItem *FormInvHead = NULL;
extern Character *Location;
Attitude *attTree = NULL;
ID gchAutoNumber = 1;
BOOL LastAttFound;
MindDefNodeP mparr[MAX_MINDSETS];
int nMindNodesNo = 0, nCurSelMindset = -1;
extern BOOL gbNoInit;
char Msg1[120];

//---------------------------------------------------------------------------
__fastcall TCharacterForm::TCharacterForm(TComponent* Owner)
	: TForm(Owner)
{
    TIniFile *pIniFile = new TIniFile("befmp.ini");
    chExternalInit = FALSE;
    memset(mparr,0,MAX_MINDSETS);
    User1Label->Caption = pIniFile->ReadString("UserParm", "Parameter1",
        User1Label->Caption);
    User2Label->Caption = pIniFile->ReadString("UserParm", "Parameter2",
        User2Label->Caption);
    User3Label->Caption = pIniFile->ReadString("UserParm", "Parameter3",
        User3Label->Caption);
    WickAnar->Caption = "";
    delete pIniFile;
}

//---------------------------------------------------------------------------
void __fastcall TCharacterForm::AnarAlChange(TObject *Sender)
{
	AlignmentDesc();
}

//---------------------------------------------------------------------------
void TCharacterForm::AlignmentDesc()
{
    switch(AnarAl->ItemIndex)
    {
        case 0: //lawful
            ChaosVal->Text = AnsiString(-75);
            switch(WickAl->ItemIndex)
            {
                case 0://good
                    AlName->Caption = "A typical \"good guy\".";
                    EvilVal->Text = AnsiString(-75);
                    break;
                case 1://neutral
                    AlName->Caption = "An average citizen - don't hurt him and you won't hear from him.";
                    EvilVal->Text = AnsiString(0);
                    break;
                case 2://evil
                    AlName->Caption = "A cold law obeying villain.";
                    EvilVal->Text = AnsiString(75);
                    break;
            }
            break;
        case 1: //neutral
            ChaosVal->Text = AnsiString(0);
            switch(WickAl->ItemIndex)
            {
                case 0:
                    AlName->Caption = "Just a good person, with no respect or disrespect for law.";
                    EvilVal->Text = AnsiString(-75);
                    break;
                case 1:
                    AlName->Caption = "A \"philosopher with no principles\" type";
                    EvilVal->Text = AnsiString(0);
                    break;
                case 2:
                    AlName->Caption = "A villain who can either obey or break laws.";
                    EvilVal->Text = AnsiString(75);
                    break;
            }
            break;
        case 2: //chaotic
            ChaosVal->Text = AnsiString(75);
            switch(WickAl->ItemIndex)
            {
                case 0:
                    AlName->Caption = "A good person, having trouble with obeying laws.";
                    EvilVal->Text = AnsiString(-75);
                    break;
                case 1:
                    AlName->Caption = "A madman with totally unpredictable behavior.";
                    EvilVal->Text = AnsiString(0);
                    break;
                case 2:
                    AlName->Caption = "Enemy of all good and organized - a walking trouble.";
                    EvilVal->Text = AnsiString(75);
                    break;
            }
            break;
    }
    nCurSelMindset = -1;
}

//---------------------------------------------------------------------------
void __fastcall TCharacterForm::WickAlChange(TObject *Sender)
{
	AlignmentDesc();
}

//---------------------------------------------------------------------------
void __fastcall TCharacterForm::OkButtonClick(TObject *Sender)
{
    char VerboseMsg[150];
    Character *NewCharacter;
    Core core;
    percentage Wickedness,Anarchy;

    AttitudeEditExit(NULL);//so the last attitude wouldn't be lost
	NewCharacter = new Character;
    gchAutoNumber = (unsigned short)(Character::cAutoNumber + 1);

    Wickedness = (percentage)EvilVal->Text.ToInt();
    Anarchy    = (percentage)ChaosVal->Text.ToInt();

    memset(&core,0,sizeof(Core));
    core.Wickedness = Wickedness;
    core.Anarchy = Anarchy;
    core.Beauty = (percentage)(rBeauty->Text.ToInt());
	core.Meanness[0] = (percentage)(sMeanness->Text.ToInt());
	core.Meanness[1] = (percentage)(rMeanness->Text.ToInt());
    core.Wealth[0] = (percentage)(sWealth->Text.ToInt());
    core.Wealth[1] = (percentage)(rWealth->Text.ToInt());
    core.Intelligence[0]  = (percentage)(sIntel->Text.ToInt());
    core.Intelligence[1] = (percentage)(rIntel->Text.ToInt());
    core.Courage = (percentage)(rCourage->Text.ToInt());
    core.Foreignness = 0;
    core.attPersonal = attTree;//CopyAttitudeTree(attTree);
    core.UserDefined[0] = (percentage)(UserDef1->Text.ToInt());
    core.UserDefined[1] = (percentage)(UserDef2->Text.ToInt());
    core.UserDefined[2] = (percentage)(UserDef3->Text.ToInt());
    if(nCurSelMindset != -1)
        core.alType = (ID)(CUSTOM_MINDSET_START +
            mparr[nCurSelMindset]->MindID);
    else
        core.alType = 0;

    NewCharacter->IsPlayerCharacter = IsPC->Checked;
    strncpy(NewCharacter->szName,CharName->Text.c_str(),MAX_NAME_LEN);
    NewCharacter->Cash = Cash->Text.ToDouble();
    NewCharacter->InventoryHead = FormInvHead;
    SetMoneyInInv(&(NewCharacter->InventoryHead), NewCharacter->Cash);
    NewCharacter->SetBEScores(core);  //only after everything is ready

    if(ItemBtn->Visible == false)   //Location mode
    {
        if(Location != NULL)
            delete Location;
        Location = new Character;
        memcpy(Location ,NewCharacter,sizeof(Character));
    }
    else
    {
        if(chExternalInit)
        {
            NewCharacter->BEStuff.GetCoreAddress()->attId
                = cnCurrent->ch.BEStuff.GetCoreAddress()->attId;
    	    SetCharacter(*NewCharacter);
        }
        else
    	    AddCharacter(*NewCharacter);
    }

	lstPrint("******************************************");
    if(CharacterForm->ItemBtn->Visible == false)   //Location mode
        sprintf(VerboseMsg,"** Location: %s",NewCharacter->szName);
    else
    {
        sprintf(VerboseMsg,"**           Character Sheet");
        lstPrint(VerboseMsg);
        sprintf(VerboseMsg,"** Name: %s",NewCharacter->szName);
    }

	lstPrint(VerboseMsg);
    PrintCharacterInfo(NewCharacter);
    NewCharacter->BEStuff.SetAttitudesRoot(NULL,TRUE);
	delete NewCharacter;
}

//---------------------------------------------------------------------------
void __fastcall TCharacterForm::FormActivate(TObject *Sender)
{
    CharacterNode cn;
    BOOL bNameAlreadyExists;
    int i = 0;
    //initialize all
	ItemForm->itAutoNumber = 0;
    FormInvHead = NULL;
    cnCurrent = CharListHead;
    if(cnCurrent == NULL)
        NextBtn->Enabled = false;
    else
        NextBtn->Enabled = true;
    IsPC->Checked = false;
    OkButton->Caption = "&Add";
    DelBtn->Enabled = false;
    chExternalInit = false;

	WickAl->ItemIndex = 1;
	AnarAl->ItemIndex = 0;
    AlignmentDesc();
    if(ItemBtn->Visible == true)
    {
        do{
            CharName->Text = RandomName();
            bNameAlreadyExists = FALSE;
            for(cn = CharListHead; cn != NULL; cn = cn->next)
                if(strcmp(CharName->Text.c_str(),cn->ch.szName) == 0)
                {
                    bNameAlreadyExists = TRUE;
                    break;
                }
            i++;
        } while(bNameAlreadyExists && (i < 10000));

    }
    else
    {
        Character::cAutoNumber--;
        CharName->Text = "**Location**";
    }
    rBeauty->Text = AnsiString((int)AVG_SCORE);
    sBeauty->Text = AnsiString((int)AVG_SCORE);
    rIntel->Text = AnsiString((int)AVG_SCORE);
    sIntel->Text = AnsiString((int)AVG_SCORE);
    rCourage->Text = AnsiString((int)AVG_SCORE);
    sCourage->Text = AnsiString((int)AVG_SCORE);
	sMeanness->Text = AnsiString((int)AVG_SCORE);
	rMeanness->Text = AnsiString((int)AVG_SCORE);
    UserDef1->Text = "0";
    UserDef2->Text = "0";
    UserDef3->Text = "0";
    Cash->Text = AnsiString((double)AVG_PRICE*2.5);
    CashChange(NULL);
    ResetCharactersList();
    DisplayInventory();
}
//---------------------------------------------------------------------------
void __fastcall TCharacterForm::ItemBtnClick(TObject *Sender)
{
	InventoryItem *NewItem;
    gbNoInit = false;
	if(ItemForm->ShowModal() == mrOk)
    {
		NewItem = new InventoryItem;
        if(NewItem == NULL)
        	return;
        SaveItem(NewItem);
        NewItem->next = FormInvHead;
        FormInvHead = NewItem;
    }
    DisplayInventory();
}

//---------------------------------------------------------------------------
void TCharacterForm::DisplayInventory()
{
	InventoryItem *iip;
	InventoryList->Clear();
	for(iip = FormInvHead ; iip != NULL ; iip = iip->next)
    	InventoryList->Items->Add( AnsiString((char*)iip->Descr) );
    if(InventoryList->Items->Count > 0)
    {
        if(InventoryList->ItemIndex < 0)
            InventoryList->ItemIndex = 0;
        DelInvBtn->Enabled = true;
        EditInvBtn->Enabled = true;
    }
    else
    {
        DelInvBtn->Enabled = false;
        EditInvBtn->Enabled = false;
    }
}

//---------------------------------------------------------------------------

void __fastcall TCharacterForm::CashChange(TObject *Sender)
{
    if(Cash->Text.c_str()[0] == '\0')
    {
        rWealth->Text = "0";
        sWealth->Text = "0";
    }
    else
    {
        rWealth->Text = AnsiString((int)Price2WealthPts(Cash->Text.ToDouble()));
        sWealth->Text = rWealth->Text;
    }
    rWealth->Update();
}
//---------------------------------------------------------------------------
void __fastcall TCharacterForm::SetAttTpChange(TObject *Sender)
{

    percentage nAtt;
    AttitudeEdit->Text = "0";
    ReferTo = GetCharacter((int)SetAttTp->ItemIndex);
    if(ReferTo)
        AttitudeEdit->Enabled = true;
    else
    {
        AttitudeEdit->Enabled = false;
        return;
    }

    nAtt = GetAttitude(ReferTo->BEStuff.GetCore().attId, attTree);
    if(nAtt == ERROR_PERCENTAGE)
    {
        LastAttFound = FALSE;
        nAtt = 0;
    }
    else
        LastAttFound = TRUE;

    AttitudeEdit->Text = AnsiString((int)nAtt);
}

//---------------------------------------------------------------------------
void TCharacterForm::ResetCharactersList()
{
    CharacterNode cn;
    ReferTo = NULL;
    attTree = NULL;//disconnect the tree root from the new tree
    SetAttTp->Items->Clear();
    SetAttTp->ItemIndex = 0;
    AttitudeEdit->Text = "0";
    for(cn = CharListHead; cn != NULL ; cn = cn->next)
        if(cn != cnCurrent || !chExternalInit)//shouldn't display attitude to self
            SetAttTp->Items->Add(cn->ch.szName);
}

//---------------------------------------------------------------------------

void __fastcall TCharacterForm::AttitudeEditExit(TObject *Sender)
{
    short nAtt;
    if(ReferTo == NULL)
        return;

    if(!AttitudeEdit->Modified)//nothing to do
        return;

    if(AttitudeEdit->Text == "")
    {
        nAtt = 0;
    }
    else
    {
        nAtt = (percentage)AttitudeEdit->Text.ToInt();
        AttitudeEdit->Text = AnsiString((int)nAtt);
    }
    UpdateAttitude(ReferTo->BEStuff.GetCore().attId,nAtt,&attTree);
}
//---------------------------------------------------------------------------
void __fastcall TCharacterForm::FormCreate(TObject *Sender)
{
    int i;

    nMindNodesNo = FillBufferWithMindPtrs(mparr,MAX_MINDSETS);
    if(!nMindNodesNo)
        return;

    CustomMind->Clear();
    CustomMind->ItemIndex = 0;
    for(i = 0; i < nMindNodesNo ; i++ )
        if(mparr[i])
            CustomMind->Items->Add((char*)mparr[i]->Descr);

}
//---------------------------------------------------------------------------
void __fastcall TCharacterForm::CustomMindChange(TObject *Sender)
{
    if(mparr[CustomMind->ItemIndex] == NULL)
    {
        WickAnar->Caption = "";
        AlName->Caption = "";
        return;
    }

    nCurSelMindset = CustomMind->ItemIndex;
    WickAnar->Caption =
        "Evil = "
        + AnsiString((int)mparr[nCurSelMindset]->LWick)
        + " to "
        + AnsiString((int)mparr[nCurSelMindset]->HWick)
        + ", chaos = "
        + AnsiString((int)mparr[nCurSelMindset]->LAnar)
        + " to "
        + AnsiString((int)mparr[nCurSelMindset]->HAnar);

    EvilVal->Text = AnsiString((int)(mparr[nCurSelMindset]->LWick
        + mparr[nCurSelMindset]->HWick)/2);
    ChaosVal->Text = AnsiString((int)(mparr[nCurSelMindset]->LAnar
        + mparr[nCurSelMindset]->HAnar)/2);
    AlName->Caption =
        (char*)mparr[nCurSelMindset]->Descr;

}

//---------------------------------------------------------------------------
void __fastcall TCharacterForm::NextBtnClick(TObject *Sender)
{
    CharacterNode cnPrevious;
    //fill the slots
    chExternalInit = true;

    cnPrevious = cnCurrent;
    if(cnCurrent != NULL)
    {
        do {
            cnCurrent = cnCurrent->next;
            if(cnCurrent == NULL)
                cnCurrent = CharListHead;
            if(cnCurrent == NULL)
            //How can it happen?.. Nevermind, safety first!
                break;
            if(cnPrevious == cnCurrent)
            //Whoops! We're running cycles!
                break;
        } while(cnCurrent->ch.BEStuff.IsDead());
    }
    if(cnCurrent == NULL || cnCurrent->ch.BEStuff.IsDead())
    {
        Beep();
        FlashWindow(ClientHandle,TRUE);
    }
    else
    {
        LoadCharacter(&(cnCurrent->ch));
    }

}
//---------------------------------------------------------------------------
void TCharacterForm::LoadCharacter(Character *chToLoad)
{
    Core core;
    if(chToLoad == NULL)
        return;
    core = chToLoad->BEStuff.GetCore();

    rBeauty->Text = AnsiString((int)core.Beauty);
    sBeauty->Text = AnsiString((int)core.Beauty);
    rIntel->Text = AnsiString((int)core.Intelligence[0]);
    sIntel->Text = AnsiString((int)core.Intelligence[1]);
    rCourage->Text = AnsiString((int)core.Courage);
    sCourage->Text = AnsiString((int)core.Courage);
    EvilVal->Text = AnsiString((int)core.Wickedness);
    ChaosVal->Text = AnsiString((int)core.Anarchy);
    sWealth->Text = AnsiString((int)core.Wealth[0]);
    rWealth->Text = AnsiString((int)core.Wealth[1]);
    sMeanness->Text = AnsiString((int)core.Meanness[0]);
    rMeanness->Text = AnsiString((int)core.Meanness[1]);
    UserDef1->Text = AnsiString((int)core.UserDefined[0]);
    UserDef2->Text = AnsiString((int)core.UserDefined[1]);
    UserDef3->Text = AnsiString((int)core.UserDefined[2]);

    SetMindset(core.alType);

    IsPC->Checked = chToLoad->IsPlayerCharacter;
    CharName->Text = chToLoad->szName;
    Cash->Text = chToLoad->Cash;
    FormInvHead = chToLoad->InventoryHead;

    CashChange(NULL);
    ResetCharactersList();
    attTree = core.attPersonal;//CopyAttitudeTree(attTree);
    DisplayInventory();

    DelBtn->Enabled = true;//we definitely have something to delete
    OkButton->Caption = "&Update";

    Invalidate();
    Update();
}
//---------------------------------------------------------------------------
void TCharacterForm::SetMindset(AlignmentType alType)
{
    int i;
    nCurSelMindset = -1;
    if(alType > CUSTOM_MINDSET_START)
    {
        for(i = 0; i < nMindNodesNo; i++)
            if(mparr[i]->MindID == alType)
            {
                nCurSelMindset = i;
                CustomMind->ItemIndex = nCurSelMindset;
                break;
            }
    }
    else
    {
        switch(alType){
            case alPureGood:    case alLawfulGood:
                WickAl->ItemIndex = 0;
                AnarAl->ItemIndex = 0;
                break;
            case alLawfulNeutral:
                WickAl->ItemIndex = 1;
                AnarAl->ItemIndex = 0;
                break;
            case alLawfulEvil:
                WickAl->ItemIndex = 2;
                AnarAl->ItemIndex = 0;
                break;
            case alNeutralGood:
                WickAl->ItemIndex = 0;
                AnarAl->ItemIndex = 1;
                break;
            case alTrueNeutral:
                WickAl->ItemIndex = 1;
                AnarAl->ItemIndex = 1;
                break;
            case alNeutralEvil:
                WickAl->ItemIndex = 2;
                AnarAl->ItemIndex = 1;
                break;
            case alChaoticGood:
                WickAl->ItemIndex = 0;
                AnarAl->ItemIndex = 2;
                break;
            case alChaoticNeutral:
                WickAl->ItemIndex = 1;
                AnarAl->ItemIndex = 2;
                break;
            case alChaoticEvil: case alUltimateEvil:
                WickAl->ItemIndex = 2;
                AnarAl->ItemIndex = 2;
                break;
        }
    }
}
//---------------------------------------------------------------------------
void __fastcall TCharacterForm::DelBtnClick(TObject *Sender)
{
    CharacterNode cnNext;
    if(cnCurrent == NULL)
        return;
    cnNext = cnCurrent->next;
    if(ChoiceYN("Are you sure?","Delete this character"))
    {
        DelCharacter(cnCurrent->ch.BEStuff.GetCore().attId);
    }
    cnCurrent = cnNext;
    if(cnCurrent == NULL)
    {
        cnCurrent = CharListHead;
        if(cnCurrent == NULL)
        {
            MessageBox(NULL,"No characters left. Exiting",
                "Love this button, heh?",MB_OK + MB_TASKMODAL);
            Close();
        }
    }
    LoadCharacter(&(cnCurrent->ch));
}

//---------------------------------------------------------------------------
void TCharacterForm::PrintCharacterInfo(Character *ch)
{
    Core core;
    char VerboseMsg[120];
    core = ch->BEStuff.GetCore();
    sprintf(VerboseMsg,"** %s",ch->szName);
	lstPrint(VerboseMsg);
    sprintf(VerboseMsg,"** Wickedness=%d, Anarchy=%d",core.Wickedness,core.Anarchy);
	lstPrint(VerboseMsg);
    sprintf(VerboseMsg,"** Combat overall:  true=%d, seemed=%d",
        core.Meanness[1], core.Meanness[0]);
	lstPrint(VerboseMsg);
    sprintf(VerboseMsg,"** Intelligence:    true=%d, seemed=%d",
        core.Intelligence[1], core.Intelligence[0]);
	lstPrint(VerboseMsg);
    sprintf(VerboseMsg,"** Beauty: %d",
        core.Beauty);
	lstPrint(VerboseMsg);
    sprintf(VerboseMsg,"** Courage: %d",
        core.Courage);
	lstPrint(VerboseMsg);
    sprintf(VerboseMsg,"** Cash:         %.2f, seemed wealth points=%d",
        ch->Cash,
        core.Wealth[1]);
	lstPrint(VerboseMsg);
    sprintf(VerboseMsg,"** User defined: %s=%d, %s=%d, %s=%d",
        User1Label->Caption.c_str(),core.UserDefined[0],
        User2Label->Caption.c_str(),core.UserDefined[1],
        User3Label->Caption.c_str(),core.UserDefined[2]);
	lstPrint(VerboseMsg);
    ch->EnumInventory();
	lstPrint("******************************************");
    lstPrint("");
}

//---------------------------------------------------------------------------
void TCharacterForm::LoadItem(InventoryItem *ToLoad)
{
    ItemScores BEScores;
    if(ToLoad == NULL)
        return;

    ItemForm->UniqueID->Text = AnsiString((int)ToLoad->ItemID);
    ItemForm->Price->Text = AnsiString((int)ToLoad->Price);
    BEScores = ToLoad->BEStuff;
    ItemForm->Meanness->Text = AnsiString((int)BEScores.Meanness);
    ItemForm->Beauty->Text = AnsiString((int)BEScores.Beauty);
    ItemForm->Personality->Text = AnsiString((int)BEScores.Personality);
    ItemForm->ItemTypeSel->ItemIndex = ToLoad->_Type;
    ItemForm->ItemDesc->Text = AnsiString(ToLoad->Descr);
    Update();
}

//---------------------------------------------------------------------------
void __fastcall TCharacterForm::EditInvBtnClick(TObject *Sender)
{
    InventoryItem *ToEdit;
    if(InventoryList->Items->Count == 0)
        return;
    gbNoInit = true;
    ToEdit = GetItemN(FormInvHead,(unsigned short)InventoryList->ItemIndex);
    if(ToEdit == NULL)
        return;
    if(strcmpi(ToEdit->Descr,"money") == 0)
    {
        Beep();/*
        MessageBox(ClientHandle,"Please edit money via CASH entry",
            "Invalid choice",MB_OK + MB_TASKMODAL);*/
        return;
    }
    LoadItem(ToEdit);
    if(ItemForm->ShowModal() == mrOk)
    {
        SaveItem(ToEdit);
        DisplayInventory();
    }
}

//---------------------------------------------------------------------------
void TCharacterForm::SaveItem(InventoryItem *ToSave)
{
    ToSave->ItemID = (percentage)(ItemForm->UniqueID->Text.ToInt());
    ToSave->Price = (unsigned short)(ItemForm->Price->Text.ToInt());
    ToSave->SetBEScores(0, 0, (percentage)(ItemForm->Meanness->Text.ToInt()),
        	0, (percentage)(Price2WealthPts(ToSave->Price)),
            (percentage)(ItemForm->Beauty->Text.ToInt()),
            (percentage)(ItemForm->Personality->Text.ToInt()));
    ToSave->_Type = (ItemType)(ItemForm->ItemTypeSel->ItemIndex);
    strncpy(ToSave->Descr,ItemForm->ItemDesc->Text.c_str(),MAX_ITEM_NAME_LEN);
//        NewItem->BEStuff.Owner = (unsigned short)(Alignment::AutoNumber+1);
}

//---------------------------------------------------------------------------
void __fastcall TCharacterForm::DelInvBtnClick(TObject *Sender)
{
    InventoryItem *ToDel,*PrevItem;
    if(InventoryList->Items->Count == 0)
        return;
    gbNoInit = true;
    ToDel = GetItemN(FormInvHead,(unsigned short)InventoryList->ItemIndex,&PrevItem);
    if(ToDel == NULL)
    {
        Stop("Inventory item not found!");
        return;
    }
    if(strcmpi(ToDel->Descr,"money") == 0)
    {
        Beep();/*
        MessageBox(ClientHandle,"Please edit money via CASH entry",
            "Invalid choice",MB_OK + MB_TASKMODAL);*/
        return;
    }

    if(ChoiceYN("Are you sure?","Delete highlighted item"))
    {
        if(PrevItem == NULL)
            FormInvHead = ToDel->next;
        else
            PrevItem->next = ToDel->next;
        delete ToDel;
        DisplayInventory();
    }
}
//---------------------------------------------------------------------------
void TCharacterForm::DeleteMoney()
{
    InventoryItem *iip,*PrevItem;
    if(FormInvHead == NULL)
    PrevItem = NULL;
	for(iip = FormInvHead ; iip != NULL ; iip = iip->next)
    {
    	if(strcmpi(iip->Descr,"money") == 0)
        {
            if(PrevItem == NULL)
                FormInvHead = iip->next;
            else
                PrevItem->next = iip->next;
            delete iip;
        	break;
        }
        else
            PrevItem = iip;
    }
}

//---------------------------------------------------------------------------

