#include "project.h"

CONTYPE TOPWINDOWId = SOB_CONTAINER_NO;

SOBDATA* TOPWINDOWLastCreated;

CONTAINERINFORM  Update_TOPWINDOW, AddToParent_TOPWINDOW, Display_TOPWINDOW;
CONTAINERINFORM  UpDateChildren_TOPWINDOW;
CONTAINERSETVALUE Stretch_TOPWINDOW;

static myUInt Stretch_TOPWINDOW(SOBDATA* conData, myUInt value)
{   // conData   = address of the SOBDATA of the TOPWINDOW CONTAINER

    // you MUST do checks on the validity of the input
    // Must protect against a "user" trying to do an action on  deleted SOB

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.Stretch given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return SOB_NOK;
    }

    return sob_set_stretch(conData, value);

}

static  myUInt ReSize_TOPWINDOW(SOBDATA* conData)
{

    // We have a number of things to do here:
    // -
    //  set the display height and display width of a child
    // -
    //  set the display X and displayY of a child with respect to the containers CLIENT area
    // -
    //  set the containers minWidth and minHeight

    #if DebuggingAid
        swprintf_s(txtBuffer, szTxtBuffer, L"TOPWINDOW.ReSize\n");  ReportError(txtBuffer);
    #endif

    if (conData->subType NEQU TOPWINDOWId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, L"TOPWINDOW.ReSize\n");  ReportError(txtBuffer);
        swprintf_s(txtBuffer, szTxtBuffer, L" ***Received a: \n %ws   \n %ws  \n"
        , sob_container_to_text (conData->subType)
        , sob_type_to_text(conData->type)

        );  ReportError(txtBuffer);
        SOB.Report(conData );

        return 0;
    }

    // This objects parent has set
    // conData->displayWidth   and   conData->displayHeight

    // set the boundaries size in pixels between the
    //    container (the host) and the display/client area for its children
    RECT hostBnd = { 4,4,4,4 };

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

    // get the  size of:
    //  widest child
    //  tallest child
    //  container height & width of the

    int minWidth = 0, minHeight = 0;
    conData->minWidth = 0;
    conData->minHeight = 0;

    SOBDATA* childObject = TOPWINDOW.FirstChild(conData);

    if (  childObject )
    {
        while (childObject  )
        {
            if (childObject->minWidth >  minWidth)   minWidth = childObject->minWidth;
            if (childObject->minHeight > minHeight)   minHeight = childObject->minHeight;

            conData->minHeight += childObject->minHeight + sobBnd.top + sobBnd.bottom;
            conData->minWidth += childObject->minWidth + sobBnd.left + sobBnd.right;

            childObject = sob_get_next_child(childObject);
        }
    }

    // ---------------------------------
    // correction needed for a COLUMN orientated container

    conData->minWidth = minWidth; // +hostBnd.left + hostBnd.right;

    //  conData->minHeight += minWidth  +hostBnd.top + hostBnd.bottom;

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

    int  freeWidth = 0;
    int  freeHeight = 0;

    // ---------------------------------
    // now we can position the children

    int Xpos = sobBnd.left , Ypos = sobBnd.top;

    childObject = sob_get_first_child(conData);
    while (childObject )
    {
        // this container type can host a MENUBAR
        // A MENUBAR affect the HOST height and WIDTH
        // but does not affect anything in the  client
        if (childObject->subType EQU SOB_CONTAINER_MENU_BAR)
        {
            // we allow for the MENUBAR's height when we display this container
        }
        else
        {
            // this container does NOT manage its childrens width/height
            // except for a STRETCHED child

            childObject->displayX = Xpos;
            childObject->displayY = Ypos;

            childObject->displayHeight = childObject->minHeight;
            childObject->displayWidth = childObject->minWidth;

            if (conData->stretchSobData EQU childObject)
            {
                // for COLUMN orientated
                freeWidth = conData->displayWidth
                - childObject->minWidth
                - sobBnd.left - sobBnd.right
                - hostBnd.left; // -hostBnd.right; // true. weird

                freeHeight = conData->displayHeight - conData->minHeight  ; //  -hostBnd.top - hostBnd.bottom;;

                if (freeWidth) childObject->displayWidth += freeWidth + hostBnd.left ;
                if (freeHeight) childObject->displayHeight += freeHeight + hostBnd.bottom;
            }
            Ypos += childObject->displayHeight + sobBnd.bottom + sobBnd.top;
        }
        childObject = sob_get_next_child(childObject);
    }

    return 0;
}

static  myUInt Display_TOPWINDOW(SOBDATA* conData)
{   // conData   = & SOBDATA for the CONTAINER   being displayed

    #if DebuggingAid
        swprintf_s(txtBuffer, szTxtBuffer, L"Display_TOPWINDOW\n");  ReportError(txtBuffer);
    #endif

    sobDisplaying = 1;

    UpDateChildren_TOPWINDOW((SOBDATA*)conData);

    sob_display_top_level_window(conData->sIndex);
    sobDisplaying = 0;

    return 1;
}

CONTAINERINFORM  Open_TOPLEVEL;
static  myUInt Open_TOPLEVEL(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the MANAGER CONTAINER   being Opened
    // i.e. made the parent of container of subsequent children

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

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("Open_TOPLEVEL given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU TOPWINDOWId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("Open_TOPLEVEL given a non MANAGER object\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    ReSize_TOPWINDOW((SOBDATA*)conData);

    sob_set_pSobObj(conData);

    return SOB_OK;
}

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

CONTAINERCREATE LastWidget_TOPWINDOW;
static SOBDATA* LastWidget_TOPWINDOW()
{
    return  TOPWINDOWLastCreated;
}

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

SOBFNC_GETTEXT TOPLEVEL_SOB_GetTypeText;
static TCHAR* TOPLEVEL_SOB_GetTypeText(SOBDATA* thisSob)
{
    static TCHAR objType[] = TEXT("TOPLEVEL");
    return  objType;
}

CONTAINERGETTEXT GetTypeText_TOPWINDOW;
static  TCHAR* GetTypeText_TOPWINDOW(SOBDATA* conData)
{

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.GetTypeText given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return NULL;
    }

    if (conData->subType NEQU TOPWINDOWId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.GetTypeText given a non TOPWINDOW object\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return NULL;
    }

    return   TOPLEVEL_SOB_GetTypeText(conData);
}

static  myUInt UpDateChildren_TOPWINDOW(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the TOPWINDOW CONTAINER   being UPDATED

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

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.UpDateChildren given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU TOPWINDOWId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.UpDateChildren  given a non MANAGER object\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    ReSize_TOPWINDOW(conData);

    SOBDATA* childObject = NULL;

    childObject = TOPWINDOW.FirstChild(conData);
    while (childObject)
    {
        if ((childObject->type EQU SOB_TYPE_CONTAINER) LAND (childObject->pVtbl )   LAND(childObject->pVtbl->UpDateChildren))
        CONTAINER.UpDateChildren(childObject);
        childObject = sob_get_next_child(childObject);
    }

    return SOB_OK;
}

static  myUInt Update_TOPWINDOW(SOBDATA* conData)
{   // conData   = & SOBDATA for the CONTAINER   being updated

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("UpDate_TOPWINDOW given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU TOPWINDOWId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("UpDate_TOPWINDOW given a non MANAGER object\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    conData->pVtbl->Display(conData);

    return 0;
}

static  myUInt UpDateParent_TOPWINDOW(SOBDATA* cData)
{   // cData   = & SOBDATA for the CHILD being created

    // add this CHILD to the parent CONTAINER
    //  read    width and height
    //  set     DisplayX & DisplayY
    //          DisplayW & DisplayW

    #if DebuggingAid
        swprintf_s(txtBuffer, szTxtBuffer, L"UpDateParent_TOPWINDOW\n");  ReportError(txtBuffer);
    #endif

    if ( cData->ppSobData->subType NEQU TOPWINDOWId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, L"UpDateParent_TOPWINDOW\n");  ReportError(txtBuffer);
        swprintf_s(txtBuffer, szTxtBuffer, L" ***Received a: \n %ws   \n %ws  \n"
        , sob_container_to_text(cData->ppSobData->subType)
        , sob_type_to_text(cData->ppSobData->type)

        );  ReportError(txtBuffer);
        return 0;
    }

    SOBDATA* pData = cData->ppSobData;

    (void)Update_TOPWINDOW(pData);
    return 1;

    if (!pData->nbrChildren)
    {
        pData->minHeight = 0;
        pData->minWidth = 0;
        return 0;
    }

    int  width = 0, height = 0;
    int i = 0;
    SOBID childId = 0;

    if (cData->subType EQU SOB_CONTAINER_MENU_BAR)
    {
        swprintf_s(txtBuffer, szTxtBuffer, L"TLC  fnAddToParent SOB_CONTAINER_MENU_BAR\n"   );  ReportError(txtBuffer);
        return 0;
    }

    // since we are managing a COLUMN, then CONTAINER grows downwards
    // i.e. in height
    pData->minHeight += cData->minHeight + tEdge + bEdge;
    // pData->minWidth += cData->minWidth;

    // want the CONTAINER WIDTH to be width of the widest child
    // if (cData->minHeight > pData->minHeight) pData->minHeight = cData->minHeight;
    if ((cData->minWidth + lEdge + rEdge) > pData->minWidth) pData->minWidth = cData->minWidth + lEdge + rEdge;

    // ---------------------------------
    // we do NOT manage the child's size

    cData->displayHeight = cData->minHeight;
    cData->displayWidth = cData->minWidth;

    // ---------------------------------
    // we do manage the child's position

    //  cData->displayX = 0 + lEdge ;
    //  cData->displayY = pData->nextY + tEdge;

    //    pData->displayWidth = pData->minWidth;
    //    pData->displayHeight = pData->minHeight;

    // ---

    return 0;
}

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

CONTAINERGETSOBDATA FirstChild_TOPWINDOW;

static  SOBDATA* FirstChild_TOPWINDOW(SOBDATA* conData)
{
    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.FirstChild given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return NULL;
    }

    if (conData->subType NEQU TOPWINDOWId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.FirstChild given a non TOPWINDOW object\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return NULL;
    }

    return  conData->headLink;
}

CONTAINERINFORM DeleteChildren_TOPWINDOW;
static myUInt  DeleteChildren_TOPWINDOW(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the   CONTAINER  whose children are to be DELETED

    return  CONTAINER.DeleteChildren(conData);

}

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

CONTAINERINFORM  Open_TOPWINDOW;
static  myUInt Open_TOPWINDOW(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the MANAGER CONTAINER   being Opened
    // i.e. made the parent of container of subsequent children

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

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.open given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->type NEQU SOB_TYPE_CONTAINER)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.open given a non MANAGER object\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    sob_set_pSobObj(conData);

    return SOB_OK;
}

static  myUInt Delete_TOPWINDOW(SOBDATA* conData)
{   // conData   = & SOBDATA for the CONTAINER   being displayed

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.Delete given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU TOPWINDOWId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("TOPWINDOW.Delete given a non TOPWINDOW object\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return SOB_NOK;
    }

    int  childNbr = 0;
    SOBDATA* childObject = TOPWINDOW.FirstChild(conData);

    while (childObject)
    {
        if (childObject->type EQU SOB_TYPE_CONTAINER)
        {
            // swprintf_s(txtBuffer, szTxtBuffer, L" DELETE child CON  %d\n", childObject->sIndex);  ReportError(txtBuffer);
            childObject->ppSobData->pVtbl->Delete(childObject);
        }
        else
        {
            // swprintf_s(txtBuffer, szTxtBuffer, L" DELETE child    %d\n", childObject->sIndex);  ReportError(txtBuffer);
            sobObj_delete(childObject);
        }

        childObject = sob_get_first_child(conData);
    }

    SOBDATA* pData = conData->ppSobData;
    sobObj_delete(conData);

    return SOB_OK ;
}

static PVTBL2T* get_container_vtbl()
{
    static PVTBL2T conTable;
    static int  conTableFlag = 0;

    if (!conTableFlag)
    {

        conTable.AddChild = UpDateParent_TOPWINDOW;
        conTable.Update = Update_TOPWINDOW;
        conTable.Display = Display_TOPWINDOW;
        conTable.Delete = Delete_TOPWINDOW;
        //     conTable.TypeText = Stretch_TOPWINDOW ;

        conTable.Stretch = Stretch_TOPWINDOW;
        // create
        conTable.ReSize = ReSize_TOPWINDOW;
        conTable.UpDateChildren = UpDateChildren_TOPWINDOW;

        conTable.Open = Open_TOPLEVEL;
        conTable.LastWidget = LastWidget_TOPWINDOW;

        conTable.FirstChild = FirstChild_TOPWINDOW;

        conTableFlag = 1;
    }
    return &conTable;
}

static SOBDATA*  sob_con_top_level_window_new(TCHAR* Title, TCHAR* WindowClass)
{

    if (TOPWINDOWId EQU SOB_CONTAINER_NO)
    {
        //  if (!TOPWINDOWId)   TOPWINDOWId = int_next_contype();

        TOPWINDOWId = SOB_CONTAINER_WINDOW;
    }

    SOBDATA * sData = sob_new_new (SOB_TYPE_CONTAINER, TOPWINDOWId, 0 , 0 );
    if (sData EQU NULL) return NULL;

    sData->pVtbl = (MNGR_METHOD_TABLE_GENERIC*) get_container_vtbl();

    sData->minWidth = CW_USEDEFAULT;
    sData->minWidth = CW_USEDEFAULT;

    sData->minWidth = CW_USEDEFAULT;
    sData->minWidth = CW_USEDEFAULT;

    sData->hWnd = CreateWindowExW
    (0
    , WindowClass
    , Title
    , WS_OVERLAPPEDWINDOW |WS_CLIPCHILDREN  //  | WS_HSCROLL | WS_VSCROLL
    , CW_USEDEFAULT
    , CW_USEDEFAULT
    , CW_USEDEFAULT
    , CW_USEDEFAULT
    , NULL
    , NULL
    , appHInst
    ,   sData
    );






    WINDOWINFO myWI = {0};
    myWI.cbSize = sizeof(WINDOWINFO);
    GetWindowInfo(sData->hWnd, &myWI);
    sData->displayX = myWI.rcWindow.left;
    sData->displayY = myWI.rcWindow.top;

    sData->displayHeight = myWI.rcWindow.bottom - myWI.rcWindow.top;
    sData->displayWidth = myWI.rcWindow.right - myWI.rcWindow.left;

    TOPWINDOWLastCreated = sData;
    return sData ;
}

CONTAINERCREATE2T  Create_TOPWINDOW;
static  SOBDATA* Create_TOPWINDOW(TCHAR* Title, TCHAR* WindowClass)
{
    return   sob_con_top_level_window_new(  Title,  WindowClass) ;
}

PVTBL2T   TOPWINDOW =
{
    UpDateParent_TOPWINDOW
    , Update_TOPWINDOW
    , Delete_TOPWINDOW
    , Display_TOPWINDOW
    , GetTypeText_TOPWINDOW
    , Stretch_TOPWINDOW
    , ReSize_TOPWINDOW
    , UpDateChildren_TOPWINDOW
    , Open_TOPWINDOW
    , LastWidget_TOPWINDOW
    , FirstChild_TOPWINDOW
    , DeleteChildren_TOPWINDOW
    , Create_TOPWINDOW
};

