//---------------------------------------------------------------------------
//  Loader.h - loads the theme data into shared memory
//---------------------------------------------------------------------------
#pragma once
//---------------------------------------------------------------------------
#include "Parser.h"
#include "TmSchema.h"
#include "ThemeFile.h"
//---------------------------------------------------------------------------
#define THEMEDATA_VERSION   0x00010006
//---------------------------------------------------------------------------
#define TM_FONTCOUNT    (TMT_LASTFONT - TMT_FIRSTFONT + 1)
#define TM_SIZECOUNT    (TMT_LASTSIZE - TMT_FIRSTSIZE + 1)
#define TM_BOOLCOUNT    (TMT_LASTBOOL - TMT_FIRSTBOOL + 1)
#define TM_STRINGCOUNT  (TMT_LASTSTRING - TMT_FIRSTSTRING + 1)
#define TM_INTCOUNT     (TMT_LASTINT - TMT_FIRSTINT + 1)
//---------------------------------------------------------------------------
class CRenderObj;       // forward
class CImageFile;       // forward
struct DIBINFO;   // forward
//---------------------------------------------------------------------------
struct THEMEMETRICS
{
    //---- subset of system metrics ----
    LOGFONT lfFonts[TM_FONTCOUNT];
    COLORREF crColors[TM_COLORCOUNT];
    int iSizes[TM_SIZECOUNT];
    BOOL fBools[TM_BOOLCOUNT];

    //---- special theme metrics ----
    int iStringOffsets[TM_STRINGCOUNT];
    int iInts[TM_INTCOUNT];
};
//---------------------------------------------------------------------------
struct LOADTHEMEMETRICS : THEMEMETRICS
{
    CWideString wsStrings[TM_STRINGCOUNT];
};

//---------------------------------------------------------------------------
// Signatures for quick cache file validation
const CHAR kszBeginCacheFileSignature[] = "BEGINTHM";
const CHAR kszEndCacheFileSignature[] = "ENDTHEME";
const UINT kcbBeginSignature = sizeof kszBeginCacheFileSignature - 1;
const UINT kcbEndSignature = sizeof kszEndCacheFileSignature - 1;

//---------------------------------------------------------------------------
// Theme section flags
#define SECTION_READY           1
#define SECTION_GLOBAL          2
#define SECTION_HASSTOCKOBJECTS 4

//---------------------------------------------------------------------------
struct THEMEHDR
{
    //---- theme validity ----
    CHAR szSignature[kcbBeginSignature];        // "BEGINTHM"
    DWORD dwVersion;            // THEMEDATA_VERSION
    DWORD dwFlags;              // must have SECTION_READY to be usable
    DWORD dwCheckSum;           // byte-additive total of all bytes following THEMEHDR
    FILETIME ftModifTimeStamp;  // Last modification time of the .msstyles file

    DWORD dwTotalLength;        // total number of bytes of all data (incl. header & begin/end sigs)

    //---- theme id ----
    int iDllNameOffset;         // dll filename of this theme
    int iColorParamOffset;      // color param theme was loaded with
    int iSizeParamOffset;       // size param theme was loaded with
    DWORD dwLangID;             // User lang ID theme was loaded with
    int iLoadId;                // sequential number for each loaded file (workstation local)

    //---- main sections ----
    DWORD iStringsOffset;       // offset to strings
    DWORD iStringsLength;       // total bytes in string section
    DWORD iSectionIndexOffset;  // offset to Section Index
    DWORD iSectionIndexLength;  // length of section indexes
    
    DWORD iGlobalsOffset;           // offset to [globals] section (for globals parts)
    DWORD iGlobalsTextObjOffset;    // offset to text obj for [globals] section
    DWORD iGlobalsDrawObjOffset;    // offset to draw obj for [globals] section

    DWORD iSysMetricsOffset;    // offset to [SysMetrics] section (for theme metrics API support)
};

//---------------------------------------------------------------------------
struct DRAWOBJHDR       // preceeds each draw obj
{
    int iPartNum;
    int iStateNum;
};
//---------------------------------------------------------------------------
struct RGNDATAHDR       // preceeds each draw obj
{
    int iPartNum;
    int iStateNum;
    int iFileIndex;   // for multiple image selection (HDC scaling)
};
//---------------------------------------------------------------------------
//   Shared Theme Data layout:
//
//      // ----- header ----
//      THEMEHDR ThemeHdr;
//
//      // ----- string section ----
//      DWORD dwStringsLength;  // length of string section
//      WCHAR [];               // strings
//
//      // ----- index section ----
//      DWORD dwIndexLengh;     // length of index section
//      DWORD dwIndexCount;     // count of APPCLASSLIVE entries
//      APPCLASSLIVE [];
//
//      // ----- theme data section ----
//      DWORD dwDataLength;     // length of theme data section
//      BYTE [];                // actual theme data
//
//      // ----- end signature
//      CHAR[8];                // ENDTHEME signature
//---------------------------------------------------------------------------
//   A class section within the "theme data section" consists of the
//   following ENTRYs:
//
//      <part jump table>
//
//      <optional state jump table>
//      <property/value entries>
//
//      for each packed drawobject:
//
//          <TMT_RGNLIST entries>      (associated with each DIB)
//          <TMT_STOCKBRUSH entries>   (associated with each DIB)
//          <TMT_DRAWOBJ entry>
//
//      <TMT_TEXTOBJ entries>
//      
//      <end of class marker>
//---------------------------------------------------------------------------
// an ENTRY consists of (all 1-byte aligned):
//
//      WORD usTypeNum;             // declared type id
//      BYTE ePrimVal;              // equiv. primitive type
//      BYTE bFiller;               // # of bytes added after data to align it
//      DWORD dwDataLen;            // includes filler bytes
//      //---- entry data follows ----
//
//---------------------------------------------------------------------------
//  The data for a part jump table ENTRY (TMT_PARTJUMPTABLE) consists of:
//
//      <offset of first drawobj: long>
//      <PartCount (1 + MaxPart): BYTE>
//      <offset to each part's entries: long[]>
//---------------------------------------------------------------------------
//  The data for a state jump table ENTRY (TMT_STATEJUMPTABLE) consists of:
//
//      <StateCount (1 + MaxState): BYTE>
//      <offset to each state's entries: long[]>
//---------------------------------------------------------------------------
//  The data for a rgn list ENTRY (TMT_RGNLIST) consists of:
//
//      <StateCount (1 + MaxState): BYTE>
//      <offset to each state's custom rgn data: long[]>
//---------------------------------------------------------------------------
//  The custom rgn data ENTRY (TMT_RGNDATA) consists of:    
//
//      RGNDATAHDR RgnDataHdr;
//      BYTE Data[];
//---------------------------------------------------------------------------
//  The TMT_STOCKBRUSHES ENTRY consists of:    
//
//    int iBrushCount;                    // number of brush slots (5*ImageCount)
//    HBRUSHES hBrushes[iBrushCount];
//---------------------------------------------------------------------------
#define MAX_SHAREDMEM_SIZE (3000*1000)            // 1.5 meg (yikes!)
//---------------------------------------------------------------------------
#ifdef _WIN64
#define ALIGN_FACTOR   8
#else
#define ALIGN_FACTOR   4   
#endif
//---------------------------------------------------------------------------
#define MAX_ENTRY_NESTING  5      // max # of nested entry levels
//---------------------------------------------------------------------------
#define ENTRYHDR_SIZE     (sizeof(SHORT) + sizeof(BYTE) + sizeof(BYTE) + sizeof(int))
//---------------------------------------------------------------------------
struct UNPACKED_ENTRYHDR      // (hdr's in theme are PACKED)
{
    WORD usTypeNum;             // declared type id
    BYTE ePrimVal;              // equiv. primitive type
    BYTE bFiller;               // # of bytes added after data to align it
    DWORD dwDataLen;            // includes filler bytes
};
//---------------------------------------------------------------------------
inline void FillAndSkipHdr(MIXEDPTRS &u, UNPACKED_ENTRYHDR *pHdr)
{
    pHdr->usTypeNum = *u.ps++;
    pHdr->ePrimVal = *u.pb++;
    pHdr->bFiller = *u.pb++;
    pHdr->dwDataLen = *u.pi++;
}
//---------------------------------------------------------------------------
struct PART_STATE_INDEX
{
    int iPartNum;          // 0=parent part
    int iStateNum;
    int iIndex;
    int iLen;
};
//---------------------------------------------------------------------------
struct APPCLASSLIVE        
{
    //---- note: cannot use ptrs since image shared by diff addr-mapping processes ----
    DWORD dwAppNameIndex;
    DWORD dwClassNameIndex;
    int iIndex;
    int iLen;
};
//---------------------------------------------------------------------------
struct APPCLASSLOCAL
{
    CWideString csAppName;
    CWideString csClassName;
    int iMaxPartNum;
    CSimpleArray<PART_STATE_INDEX> PartStateIndexes;
    int iPackedSize;        // total size of section (incl strings) if packed

    APPCLASSLIVE LiveIndex;     // updated during copy to live
}; 
//---------------------------------------------------------------------------
HRESULT InitThemeMetrics(LOADTHEMEMETRICS *tm);
void SetSystemMetrics(THEMEMETRICS *tm, BOOL fSyncLoad);
HRESULT PersistSystemColors(THEMEMETRICS *tm);
//---------------------------------------------------------------------------
class CThemeLoader : IParserCallBack
{
public:
    CThemeLoader();
    ~CThemeLoader();

    HRESULT LoadTheme(LPCWSTR pszThemeName, LPCWSTR pszColorParam,
        LPCWSTR pszSizeParam, OUT HANDLE *pHandle, BOOL fGlobalTheme);

    BOOL GetThemeName(LPTSTR NameBuff, int BuffSize);

    HRESULT SetWindowThemeInfo(HWND hwnd, LPCWSTR pszThemeIdList); 
    
    HRESULT LoadClassDataIni(HINSTANCE hInst, LPCWSTR pszColorName,
        LPCWSTR pszSizeName, LPWSTR pszFoundIniName, DWORD dwMaxIniNameChars, LPWSTR *ppIniData);

    //---- IParserCallBack ----
    HRESULT AddIndex(LPCWSTR pszAppName, LPCWSTR pszClassName, 
        int iPartNum, int iStateNum, int iIndex, int iLen);

    HRESULT AddData(SHORT sTypeNum, PRIMVAL ePrimVal, const void *pData, DWORD dwLen);
    int GetNextDataIndex();

protected:
    //---- helpers ----
    HRESULT PackAndLoadTheme(LPCWSTR pszThemeName, LPCWSTR pszColorParam,
        LPCWSTR pszSizeParam, HINSTANCE hInst);
    HRESULT CopyLocalThemeToLive(int iTotalLength, LPCWSTR pszThemeName, 
        LPCWSTR pszColorParam, LPCWSTR pszSizeParam);
    void FreeLocalTheme();
    HRESULT PackMetrics();
    HRESULT PackThemeStructs();

    BOOL KeyDrawPropertyFound(int iStateDataOffset);
    BOOL KeyTextPropertyFound(int iStateDataOffset);

    HRESULT PackDrawObject(MIXEDPTRS &u, CRenderObj *pRender, int iPartId, int iStateId);
    HRESULT PackTextObject(MIXEDPTRS &u, CRenderObj *pRender, int iPartId, int iStateId);

    HRESULT PackDrawObjects(MIXEDPTRS &u, CRenderObj *pRender, int iMaxPart, BOOL fGlobals);
    HRESULT PackTextObjects(MIXEDPTRS &u, CRenderObj *pRender, int iMaxPart, BOOL fGlobals);

    HRESULT CopyPartGroup(APPCLASSLOCAL *ac, MIXEDPTRS &u, int iPartNum, 
        int *piPartJumpTable, int iPartZeroIndex, int iGlobalsIndex, BOOL fGlobalsGroup);

    int GetPartOffset(CRenderObj *pRender, int iPartNum);

    HRESULT CopyClassGroup(APPCLASSLOCAL *ac, MIXEDPTRS &u, int iGlobalsIndex, int iClassNameOffset);
    int GetMaxState(APPCLASSLOCAL *ac, int iPartNum);

    HRESULT AddIndexInternal(LPCWSTR pszAppName, LPCWSTR pszClassName, 
        int iPartNum, int iStateNum, int iIndex, int iLen);

    BOOL IndexExists(LPCWSTR pszAppName, LPCWSTR pszClassName, 
        int iPartNum, int iStateNum);

    HRESULT AddMissingParent(LPCWSTR pszAppName, LPCWSTR pszClassName, 
        int iPartNum, int iStateNum);

    HRESULT EmitEntryHdr(MIXEDPTRS &u, SHORT propnum, BYTE privnum);
    int EndEntry(MIXEDPTRS &u);

    HRESULT PackImageFileInfo(DIBINFO *pdi, CImageFile *pImageObj, MIXEDPTRS &u, 
        CRenderObj *pRender, int iPartId, int iStateId);
    
    HRESULT AllocateThemeFileBytes(BYTE *upb, DWORD dwAdditionalLen);

    // Helper functions to alloc and emit sized data
    HRESULT EmitAndCopyBlock(MIXEDPTRS &u, void *pSrc, DWORD dwLen);
    HRESULT EmitString(MIXEDPTRS &u, LPCWSTR pSrc, DWORD dwLen, int *piOffSet);
    HRESULT EmitObject(MIXEDPTRS &u, SHORT propnum, BYTE privnum, void *pHdr, DWORD dwHdrLen, void *pObj, DWORD dwObjLen);

    //---- private data ----
    CWideString _wsThemeFileName;
    int _iGlobalsOffset;
    int _iSysMetricsOffset;
    
    //---- ptrs to packed objs for [globals] section ----
    int _iGlobalsTextObj;       // we always create this obj
    int _iGlobalsDrawObj;       // we always create this obj

    //---- local copy of theme data while being built ----
    BYTE *_pbLocalData;
    int _iLocalLen;
    CSimpleArray<APPCLASSLOCAL> _LocalIndexes;

    //---- used for updating entry hdrs ----
    BYTE *_pbEntryHdrs[MAX_ENTRY_NESTING];          // points to current hdr
    int _iEntryHdrLevel;

    //---- shared memory copy of theme data ----
    CUxThemeFile _LoadingThemeFile;

    //---- theme metrics ----
    LOADTHEMEMETRICS _LoadThemeMetrics;

    //---- Global creation flag
    BOOL _fGlobalTheme;

    //---- Machine page size for VirtualAlloc optimization
    DWORD _dwPageSize;
};
//---------------------------------------------------------------------------