/*
* LaGUI: A graphical application framework.
* Copyright (C) 2022-2023 Wu Yiming
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include "la_5.h"
#include "la_tns.h"

/*                                | given to | given to    | array  |      */
/*                                |  user    | user  calls | setting|      */
/*                                | callback | and is used | needs  |      */
/*                                | callback | to recieve  | offset |      */
/*                                | callback | array config| hint   |      */
/*                                +----------+-------------+--------+      */
/*                                |   The    |             |        |      */
/*                                | DataBlock|    The      |  The   |      */
/* return value  |    Name        | Instance | Actual Data | Offset |      */
/*\             /                  \_        \             /      _/       */
/* \           /                     \_       \           /     _/         */
/*  \         /                        \_      \         /    _/           */
/*   \       /                           \_     \       /   _/             */
/*    \     /                              \     \     /  _/               */
typedef int (*laArrayGetLenF)(void *);
typedef int (*laIntGetF)(void *);
typedef void (*laIntSetF)(void *, int);
typedef void (*laIntReadF)(void *, int);
typedef void (*laIntArrayGetAllF)(void *, int *);
typedef void (*laIntArraySetF)(void *, int, int); //idx,n
typedef void (*laIntArraySetAllF)(void *, int);
typedef void (*laIntArraySetAllArrayF)(void *, int *);
typedef void (*laIntArrayReadAllF)(void *, int *);
typedef real (*laFloatGetF)(void *);
typedef void (*laFloatSetF)(void *, real);
typedef void (*laFloatReadF)(void *, real);
typedef void (*laFloatArrayGetAllF)(void *, real *);
typedef void (*laFloatArraySetF)(void *, int, real); //idx,n
typedef void (*laFloatArraySetAllF)(void *, real);
typedef void (*laFloatArraySetAllArrayF)(void *, real *);
typedef void (*laFloatArrayReadAllF)(void *, real *);
typedef int (*laEnumGetF)(void *);
typedef int (*laEnumGetLengthF)(void *);
typedef void (*laEnumSetF)(void *, int);
typedef void (*laEnumReadF)(void *, int);
typedef void (*laEnumArraySetF)(void *, int, int); //idx,n
typedef void (*laEnumArraySetAllF)(void *, int *);
typedef void (*laEnumArrayReadAllF)(void *, int *);
typedef void (*laEnumArrayGetAllF)(void *, int *);
typedef void (*laStringSetF)(void *, char *);
typedef void (*laStringGetF)(void *, char *copy_result, char** direct_result);
typedef void (*laStringReadF)(void *, char *);
typedef int (*laStringGetLenF)(void *);

typedef void (*laSubReadF)(void *, void *);         //from,set
typedef void *(*laSubGetInstanceF)(void *, void *); //from,iterator
typedef void (*laSubSetInstanceF)(void *, void *);
typedef void *(*laSubGetNextF)(void *, void *); //this,iterator
typedef int (*laSubGetAmountF)(void *);
typedef int (*laSubGetStateF)(void *);
typedef int (*laSubSetStateF)(void *, void *, int);
typedef void *(*laSubTypeDetachedGet)(void *, void *);
typedef void *(*laSubTypeDetachedGetNext)(void *, void *);
typedef void *(*laSubGetTypeF)(void *);// inst, returns type ref.
typedef int (*laSubUIFilterF)(void* parent, void* inst); // 1 show, 0 discard.
typedef int (*laSubSaveFilterF)(void* parent, void* inst); // 1 save, 0 discard.
typedef void *(*laSubUIThemeF)(void* parent, void* inst); // return a theme, MAIN.CurrentTheme can always be referenced to produce invert.
typedef int (*laSubUIGapF)(void* parent, void* inst);
typedef void (*laSubUICategoryF)(void* parent, void* inst, char *copy_result, char** direct_result);
typedef void* (*laRawGetF)(void *, int* r_size, int* return_is_a_copy);
typedef void (*laRawMultiGetF)(void *, int* r_chunks, uint32_t* r_sizes, void** pointers); // max 128 chunks
typedef int (*laRawMultiCanGetF)(void *);
typedef int (*laRawGetSizeF)(void *);
typedef void (*laRawSetF)(void *, void* data, uint32_t copy_size);

typedef void (*laContainerPostReadFunc)(void *);
typedef laPropContainer* (*laGetNodeTypeFunc)(void *);
typedef void (*laContainerBeforeFreeF)(void *);
typedef void (*laContainerResetF)(void *);
typedef void (*laContainerUndoTouchedF)(void *, u64bit hint);
typedef void (*laContainerpUDFPropagateF)(void *, void* udf, int Force);

typedef void (*laPreSaveF)();
typedef void (*laPostSaveF)();

typedef int (*laActionHolderVerifyF)(void* Holder, laPropContainer* HolderType, void* inst, laPropContainer* InstType);

#define LA_PROP_GENERAL_ROOT (1<<7)
#define LA_PROP_SUB (1<<8)
#define LA_PROP_INT (1<<9)
#define LA_PROP_FLOAT (1<<10)
#define LA_PROP_ENUM (1<<12)
#define LA_PROP_STRING (1<<13)
#define LA_PROP_ARRAY (1<<14)
#define LA_PROP_PANEL (1<<15)
#define LA_PROP_UI (1<<16)
#define LA_PROP_OPERATOR (1<<17)
#define LA_PROP_MENU (1<<18)
#define LA_PROP_SELF_CONDITION (1<<19)
#define LA_PROP_BIN (1<<20)
#define LA_PROP_REF_LIST (1<<21)
#define LA_PROP_GENERIC_BITS (~LA_PROP_ARRAY)
#define LA_PROP_IS_FOLDER (1<<22)
#define LA_PROP_IS_FILE   (1<<23)
#define LA_PROP_RAW       (1<<24)
#define LA_PROP_IS_LINEAR_SRGB (1<<24)
#define LA_PROP_READ_PROGRESS (1<<25)

#define LA_PROP_OTHER_ALLOC (1<<3)
#define LA_PROP_HYPER_BITS (1|2)

#define LA_RAW_CSTR_MAX_LEN 4096

#define LA_PROP_KEY_INTERPOLATION_ROTATION 1

typedef void (*laUiDefineFunc)(void *uil, void *collection_inst, void *this_inst, void *extra_col, int temlpate_context);
typedef void (*laPanelDetachedPropFunc)(void *panel);

//typedef void(*laUnlinkFunc)(void*, void*);//this instance,target instance

NEED_STRUCTURE(laCanvasTemplate);
NEED_STRUCTURE(laKeyMapper);


STRUCTURE(laSaverDummy){
    laListItem Item;
    real pad;
};

STRUCTURE(laPropContainer){
    laListItem Item;

    const char *Identifier;
    const char *Name;
    const char *Description;

    uint32_t IconID;

    int NodeSize;

    laContainerBeforeFreeF  BeforeFree;
    laContainerUndoTouchedF UndoTouched;
    laContainerResetF       Reset;
    laContainerpUDFPropagateF UDFPropagate;
    laContainerPostReadFunc PostRead;
    laContainerPostReadFunc PostReadIm;
    int Hyper;
    int OtherAlloc;

    laActionHolderVerifyF ActionHolderVerify;

    laCanvasTemplate *Template2D;

    laListHandle Props;

    laUiDefineFunc UiDefine;
    laUiDefineFunc MenuUiDefine;

    laListHandle FailedNodes;
    laListHandle TrashBin;
    laListHandle LocalUsers;

    int validated;
    laProp* SaverDummy;

};

NEED_STRUCTURE(laUiType);
NEED_STRUCTURE(laPanel);
NEED_STRUCTURE(laPropStep);

STRUCTURE(laPropPack){
    laPropStep *Go;
    void *EndInstance;
    laPropStep *LastPs;
    laPropPack *RawThis;
    char LastIndex;
    //char ReusedPs;
};

STRUCTURE(laProp){
    laListItem Item;
    laPropContainer *Container;

    int PropertyType;

    int ReadOnly;
    //laProp*      Detached;
    laPropPack DetachedPP;

    int Len;

    char ElementBytes;

    uint32_t IconID;

    const char *Identifier;
    const char *Name;
    const char *Description;
    const char *Prefix;
    const char *Unit;

    const char *ExtraInstructions;

    laArrayGetLenF GetLen;

    laPropContainer *SubExtra; //?
    laPropContainer *SubProp;

    laUiDefineFunc UiDefine;

    laUiType *DefaultUiType;
    int       DefaultFlags;

    int Offset;
    char OffsetIsPointer;
    char UDFIsRefer;
    char UDFNoCreate;
    char UDFIgnore;
    char UDFOnly;
    char UDFIsSingle;
    char UDFHideInSave;
    char UDFSingleManageable;
    char UDFReadProgress;
    char IsRadAngle;
    char CanTranslate;
    char Keyable;
    char KeySpecialInterpolation;

    //int           SignalThrow;
    //int           SignalCatch;

    u64bit Tag;

    laListHandle UserPanels;
};

STRUCTURE(laPropUserPanel){
    laListItem Item;
    laPanel *Panel;
    laListHandle UserPacks;
};

STRUCTURE(laPropUser){
    laListItem Item;
    laPropStep *User;
    unsigned int FrameDistinguish;
};

STRUCTURE(laPropStep){
    laPropStep *pNext;
    laProp *p;
    char Type;
    void *UseInstance;
};

STRUCTURE(laPropLink){
    laListItem Item;
    laPropPack Recieve;
    laSafeString *Identifier;
    laProp *Prop;
    laPropStep FakePS;
    laPropPack PP;
    void *DataStowage;
};

STRUCTURE(laIntProp){
    laProp Base;
    laIntGetF Get;
    laIntSetF Set;
    laIntArraySetF SetArr;
    laIntArraySetAllF SetAll;
    laIntArraySetAllArrayF SetAllArr;
    laIntArrayGetAllF GetAll;

    laIntReadF Read;
    laIntArrayReadAllF ReadAll;

    int Step;
    int Min, Max;
    int DefVal;
    const int *DefArr;

    int *Detached;
};

STRUCTURE(laFloatProp){
    laProp Base;
    laFloatGetF Get;
    laFloatSetF Set;
    laFloatArraySetF SetArr;
    laFloatArraySetAllF SetAll;
    laFloatArraySetAllArrayF SetAllArr;
    laFloatArrayGetAllF GetAll;

    laFloatReadF Read;
    laFloatArrayReadAllF ReadAll;

    real Step;

    real Min, Max;
    real DefVal;
    const real *DefArr;

    real *Detached;
};

STRUCTURE(laEnumItem){
    laListItem Item;
    const char *Identifier;
    const char *Name;
    const char *Description;
    int Index;
    uint32_t IconID;
};

STRUCTURE(laEnumProp){
    laProp Base;
    laEnumGetF Get;
    laEnumGetLengthF GetLen;
    laEnumSetF Set;
    laEnumArraySetF SetArr;
    laEnumArraySetAllF SetAll;
    laEnumArrayGetAllF GetAll;

    laEnumReadF Read;
    laEnumArrayReadAllF ReadAll;

    laListHandle Items; //id start from 1.

    int DefVal;
    const int *DefArr;

    int *Detached;
};

STRUCTURE(laStringProp){
    laProp Base;
    laStringGetF Get;
    laStringSetF Set;
    laStringGetLenF Getstrlen;

    laStringReadF Read;

    char IsSafeString;

    const char *DefStr;

    char *Detached;
};

NEED_STRUCTURE(laOperatorType)

STRUCTURE(laOperatorProp){
    laProp Base;
    const char *OperatorID;
    laOperatorType *OperatorType;
};

STRUCTURE(laRawProp){
    laProp Base;
    laRawGetF RawGet;
    laRawMultiGetF RawMultiGet; laRawMultiCanGetF RawMultiCanGet;
    laRawSetF RawSet;
    laRawGetSizeF RawGetSize;
};

STRUCTURE(laSubProp){
    laProp Base;
    laSubGetInstanceF Get;
    laSubGetInstanceF GetActive;
    laSubSetInstanceF Set;
    laSubGetNextF GetNext;
    laSubGetStateF GetState;
    laSubSetStateF SetState;
    laSubGetAmountF GetAmount;
    laSubUIFilterF UiFilter;
    laSubSaveFilterF SaveFilter;
    laSubUIThemeF GetTheme;
    laSubUIGapF GetGap;
    laSubUICategoryF GetCategory;
    int ListHandleOffset;

    laSubTypeDetachedGet DetachedGet;
    laSubTypeDetachedGetNext DetachedGetNext;

    const char *TargetID;
    laGetNodeTypeFunc GetType;

    int IsDetached;
    void *Detached;

    int IsRefList;
};

STRUCTURE(laPropIterator){
    laListItemPointer *Linker;
    void *Parent;
    void *Handle;
};


STRUCTURE(laResourceFolder){
    laListItem Item;
    laSafeString* Path;
};

STRUCTURE(laRoot){
    laPropContainer *Root;
    void *RootInstance;
};
STRUCTURE(laUDFPostRead){
    laListItem Item;
    void *Instance;
    laContainerPostReadFunc Func;
};

STRUCTURE(laPtrSync){
    laListItem Item; //hash
    void *RefDB;
    //void*     ReadRef;
    void *Parent; //key
    laSubProp *Prop;  //must be sub
};

STRUCTURE(laPtrSyncCommand){
    laListItem Item;
    laPtrSync *Target;
    void *ReadInstance;
    laUID ReadNUID;
};

STRUCTURE(laUDFPropQuickSeek){
    laListItem Item;
    laSafeString *Path;
    off_t QuickSeek;
};
STRUCTURE(laUDFPropSegment){
    laListItem Item;
    laPropPack *PPP;
    laPropPack PP;
    laSafeString *Path;
    off_t WriteQuickSeek;
};
STRUCTURE(laUDFH2Instance){
    laListItem Item;
    laPropContainer* pc;
    void* Instance;
};
STRUCTURE(laUDF){
    int Opened;
    int Extensions;
    FILE *DiskFile;
    laSafeString *FileName;

    laListHandle     H2Instances;
    laUDFH2Instance* CurrentH2Instance;
    
    laListHandle PropsToOperate;
    laListHandle QuickSeeks;
    //laListHandle  PointerSync;
    //laListHandle  PointerRecording;
    short NumSegmets;
    short Modified;
    short HasInstances;
    short Managed;

    u8bit *FileContent;
    u64bit Seek;
    u64bit FileContentSize;

    long TotalRefs;

    laListHandle HyperRecords; //writing

    //laListHandle  LinkedFiles;    //writing and reading
    laListHandle OwnHyperItems; //reading
};
STRUCTURE(laUDFHyperRecordItem){
    laListItem Item;
    void* HyperUserMem;
    laPropContainer* pc;
    u64bit Seek;
};
STRUCTURE(laUDFRegistry){
    laListItem Item;
    laSafeString* Path;
};
STRUCTURE(laUDFOwnHyperItem){
    laListItem Item;
    laUID NUID;
    laUDFRegistry* Registry;
    u64bit Seek;
};
STRUCTURE(laTrashRestoreExtra){
    void *Instance;
    laListHandle Instances;
};
STRUCTURE(laManagedUDF){
    laListItem Item;
    laUDF* udf;
    laSafeString *BaseName; // update together
    laListHandle PropSegments;
};
STRUCTURE(laManagedSaveProp){
    laListItem Item;
    laSafeString* Path;
    laListHandle SaveAlongside;
};


typedef void (*laDiffPushEverythingF)();
typedef void (*laDiffCommandUndoF)(void* Data);
typedef void (*laDiffCommandRedoF)(void* Data);
typedef void (*laDiffCommandFreeF)(void* Data, int FromOlder);
STRUCTURE(laDiffCommandCustom){
    laListItem Item;
    void* Data;
    laDiffCommandUndoF Undo;
    laDiffCommandRedoF Redo;
    laDiffCommandFreeF Free;
};
STRUCTURE(laDiff){
    laListItem Item;
    laListHandle Commands;
    laListHandle CustomCommands;
    laListHandle ExtraTouched;
    laSafeString* Description;
    u64bit Hint;
};
STRUCTURE(laDiffExtraTouched){
    laListItem Item;
    laDBInst* dbi;//ref, not owner
};;
STRUCTURE(laDiffCommand){
    laListItem Item;
    laDBInst* Instance;
    laProp* p;
    void* Data; //for sub, this is dbinst.
};
STRUCTURE(laDiffCommandRaw){
    laListItem Item;
    laDBInst* Instance;
    laProp* p;
    void* Data; int DataSize;
};
STRUCTURE(laDiffCommandInst){
    laListItem Item;
    laDBInst* OriginalPrev;
    laDBInst* OriginalNext;
    laDBInst* BeforePrev;
    laDBInst* BeforeNext;
    laDBInst* DBInst;
};
STRUCTURE(laDiffCommandSub){
    laDiffCommand Base;
    laListHandle AddedInst;
    laListHandle RemovedInst;
    laListHandle MovedInst;
};
STRUCTURE(laDiffTemp){
    laListItem Item;
    void* p;
    void* tPrev;
    void* tNext;
    void* nPrev;
    void* nNext;
};

STRUCTURE(laDBRecordedProp){
    laListItem Item;
    laSafeString* OriginalPath;
};

STRUCTURE(laDBInstPendingRelink){
    laListItem Item;
    laDBInst* dbi; void* from; void* to;
};
STRUCTURE(laDBInst){
    laListItem Item;
    laListItem Item2;//DBInstLink
    void* OriginalInstance;
    laPropContainer* pc;
    laListHandle Props;
};
STRUCTURE(laDBProp){
    laListItem Item;
    laProp*    p;
    void*      Data;
    //---------------
};
;
STRUCTURE(laDBRawProp){
    laListItem Item;
    laProp*    p;
    void*      Data;
    //---------------
    int        DataSize;
};
STRUCTURE(laDBSubProp){
    laListItem Item;
    laProp*    p;
    void*      Data;
    //---------------
    laListHandle Instances;
};

STRUCTURE(laDiffPtrSync){
    laListItem Item;
    void* instance;
    laDBProp* dbp;
    laDiffCommand* dc;
};

STRUCTURE(laDiffPost){
    laListItem Item;
    void* instance;
    laContainerUndoTouchedF Touched;
};

#define LA_ANIMATION_PLAY_MODE_REPEAT 0
#define LA_ANIMATION_PLAY_MODE_HOLD   1
#define LA_ANIMATION_PLAY_MODE_BOUNCE 2

#define LA_ANIMATION_MIX_REPLACE 0
#define LA_ANIMATION_MIX_ADD     1

NEED_STRUCTURE(laAction);
STRUCTURE(laActionHolder){
    laListItem Item;
    void* Instance; int ActionOffset,PropOffset;
    laPropContainer* Container;
    laSafeString* Name;
    laSafeString* CategoryTitle;
};
STRUCTURE(laActionHolderPath){
    laListItem Item;
    laPropPack PP;
    char* OriginalPath;
};
STRUCTURE(laAnimation){
    real _PAD;
    laAction*    CurrentAction;
    laListHandle ActionHolders;
    laListHandle ActionHolderPaths;
    real PlayHead;
    int PlayStatus;
    laTimeRecorder TimeOrigin;

    real RunPlayHead;
};
STRUCTURE(laAction){
    laListItem Item;
    laSafeString* Name;
    void* HolderInstance; laPropContainer* HolderContainer; // for verification
    laListHandle Channels;
    int FrameCount;
    real Length;
    real PlayHead,Offset;
    int PlayMode;
    int Solo, Mute;
    int PlayByDefault;
    int MixMode;
};
STRUCTURE(laActionProp){
    laListItem Item;
    void* For;
    laProp* Prop;
    int DataSize; // sizeof
    laSafeString* CachedName;
    uint64_t Data[16];
    int Reset;
};
STRUCTURE(laActionChannel){
    laListItem Item;
    laActionProp* AP;
    laListHandle Keys;
};
STRUCTURE(laActionKey){
    laListItem Item;
    int At,OriginaAt;
    int Selected;
    int DataSize;
    void* Data;
};
STRUCTURE(laRetargetedAction){
    void** Instances;
    real PlayHead;
    int PlayStatus;
    int Direction;
};
STRUCTURE(laActionRetarget){
    int DetachedInNode;
    int ActionCount;
    real PlaySync;
    laListHandle* Actions;
    laRetargetedAction* Retargeted;
    void* HolderInstance;
};

#define LA_ACTION_FRAME(aa,override_playhead) (((((override_playhead)>=0)?(override_playhead):(aa)->PlayHead)+FLT_EPSILON)*(real)((aa)->FrameCount))

/* Only little endian are supported right now */
#define LA_UDF_IDENTIFIER "UDF_LE"

#define LA_UDF_EXTENSION_FLOAT32 (1<<0)
#define LA_UDF_EXTENSION_RAW (1<<1)
#define LA_UDF_EXTENSION_QUICK_SEEK (1<<2)

#define LA_UDF_EXTENSIONS_ENABLED (LA_UDF_EXTENSION_RAW|LA_UDF_EXTENSION_QUICK_SEEK)

#define LA_UDF_ALL_EXTENSIONS 0xffff

#define LA_UDF_MARK_TIMESTAMP 3

#define LA_UDF_MODE_APPEND 0
#define LA_UDF_MODE_OVERWRITE 1

#define LA_UDF_SINGLE       (1<<0)
#define LA_UDF_COLLECTION   (1<<1)
#define LA_UDF_REFER        (1<<2)
#define LA_UDF_ITEM         (1<<3) //ItemType
#define LA_UDF_ACTIVE (1<<4)
#define LA_UDF_STATE (1<<5)
#define LA_UDF_REGULAR_MARK_64 (1<<6)
#define LA_UDF_ARRAY_MARK_64 (1<<7)
#define LA_UDF_HYPER_ITEM (1<<8)  //ItemType
#define LA_UDF_SHARE_RESOURCE (1<<9)
#define LA_UDF_USE_VERSION (1<<10) //Use History
#define LA_UDF_REGULAR_MARK_32 (1<<10)
#define LA_UDF_ARRAY_MARK_32 (1<<11)
#define LA_UDF_STRING_MARK (1<<12)
#define LA_UDF_HYPER_MARK (1<<13)
#define LA_UDF_ONLY (1<<14)
#define LA_UDF_RAW_MARK (1<<14)
//#define LA_UDF_LINKED_ITEM (1<<15) //ItemType
#define LA_UDF_IGNORE (1<<16)
#define LA_DETACHABLE (1<<17)
#define LA_UDF_VARIABLE_NODE_SIZE (1<<18)
#define LA_UDF_FIXED_NODE_SIZE (1<<19)
#define LA_UDF_LOCAL (1<<20)
#define LA_RAD_ANGLE (1<<21)
#define LA_UDF_PRINT_STATICS (1<<22)
#define LA_UDF_NUID_SEEK (1<<23)
#define LA_UDF_NUID_LINK_FILES (1<<24)
#define LA_AS_IDENTIFIER (1<<25)
#define LA_UDF_USE_LINK_NODE (1<<26)
#define LA_READ_ONLY (1<<27)
#define LA_HIDE_IN_SAVE (1<<28)
#define LA_TRANSLATE (1<<29)
#define LA_PROP_KEYABLE   (1<<30)
#define LA_PROP_ROTATION  (1<<31)

STRUCTURE(laThreadNotifier){
    laListItem Item;
    char Path[256];
};

laPropContainer *laDefineRoot();

NEED_STRUCTURE(laOperatorType)
NEED_STRUCTURE(laOperator)
NEED_STRUCTURE(laEvent)

void laset_InstanceUID(void* instance, char* buf);

void *laget_ListNext(laListItem *Item, void *UNUSED);
void *laget_ListPrev(laListItem *Item, void *UNUSED);
void *laget_List2Next(laListItem2 *Item, void *UNUSED);
void *laget_List2Prev(laListItem2 *Item, void *UNUSED);

void la_DEBUG_VerifyThisContainer(laPanel *pa, laPropContainer *pc);
void la_DEBUG_VerifyPanelPropsDestroyed(laPanel *p);

void la_CopyPropPack(laPropPack *From, laPropPack *To);
void laPropPackToLocal(laPropPack* ToPP, laPropPack* pp);

laPropContainer* la_EnsureSubTarget(laSubProp* sp, void* optional_instance);

laPropContainer *la_ContainerLookup(char *ID);
laProp *la_PropLookup(laListHandle *lst, char *ID);

void la_UsePropPack(laPropPack *pp, int ForceRecalc);
void la_StopUsingPropPack(laPropPack *pp);
void la_SetPropMathcerContext(laPanel *p);
void laNotifyUsersPP(laPropPack *pp);
void laNotifyUsersPPPath(laPropPack *pp, char *path);
void laNotifySubPropUsers(laProp *p, void *Instance);
void laNotifyUsers(char *Path);
void laNotifyInstanceUsers(void *Instance);
void laThreadNotifyUsers(char *Path);
void laNotifyDetached(void* OldInstance, void* NewInstance);
void laDetachedTrySet(char* prop_identifier,void* NewInstance);

int laIsPropertyReadOnly(laPropPack *pp);

int laGetPrefixP(laPropPack *p, char buf[8][64]);
int laGetPrefix(laProp *p, char buf[8][64]);

laPropContainer* laGetInstanceType(laPropPack* pp, void* instance);
laUiDefineFunc laGetPropertyUiDefine(laPropPack* pp, void* instance);

int laSetInt(laPropPack *pp, int n);
int laGetInt(laPropPack *pp);
int laSetFloat(laPropPack *pp, real n);
real laGetFloat(laPropPack *pp);
int laGetArrayLength(laPropPack *pp);
int laSetIntArraySingle(laPropPack *pp, int index, int n);
int laSetIntArrayAll(laPropPack *pp, int n);
int laSetIntArrayAllArray(laPropPack *pp, int *arr);
int laGetIntArray(laPropPack *pp, int *result);
int laSetFloatArraySingle(laPropPack *pp, int index, real n);
int laSetFloatArrayAll(laPropPack *pp, real n);
int laSetFloatArrayAllArray(laPropPack *pp, real *arr);
int laGetFloatArray(laPropPack *pp, real *result);
laEnumItem *laGetEnum(laPropPack *pp);
int laGetEnumEntryLen(laPropPack *pp);
laEnumItem *laGetEnumArrayIndexed(laPropPack *pp, int index);
int laGetEnumArray(laPropPack *pp, laEnumItem **result);
laEnumItem *laGetEnumFromIdentifier(laEnumProp *p, char *Identifier);
int laEnumHasIcon(laPropPack *pp);
int laSetEnumExternal(laPropPack *pp, int n);
int laSetEnum(laPropPack *pp, int n);
int laSetEnumArrayIndexedExternal(laPropPack *pp, int index, int n);
int laSetEnumArrayIndexed(laPropPack *pp, int index, int n);
int laSetEnumArrayAllArray(laPropPack* pp, laEnumItem** ei);
int laSetEnumArrayAll(laPropPack* pp, int EnumN);
int laSetString(laPropPack *pp, char *str);
int laGetString(laPropPack *pp, char *result, char** direct_result);
int laActuateProp(laPropPack *This, laPropPack *RunPP, laOperator *OptionalFrom, laEvent *e);
int laGetIntRange(laPropPack *pp, int *min, int *max);
int laGetFloatRange(laPropPack *pp, real *min, real *max);
void* laGetRaw(laPropPack *pp, int* r_size, int* return_is_a_copy);
int laSetRaw(laPropPack *pp, void* data, uint32_t _size);

int laTryGetInstanceIdentifier(void* Instance, laPropContainer* pc, char* identifier, char** here);

void laMarkPropChanged(laPropPack* pp);
void laMarkMemChanged(void* memuser);
void laMarkMemClean(void* memuser);

void *la_FindMatchingInstance(void *From, laProp *Sub, laProp *p, laPropStep *Value);

void la_FreePropStepCache(laPropStep *GoTarget);
void la_StepPropPack(laPropPack *pp);

void la_GetPropPackFullPath(laPropPack *pp, char *result);
void la_GetPropPackPath(laPropPack *pp, char *result);

laItemUserLinker *laUseDataBlock(void* HyperUserMem, laProp *Which, unsigned int FrameDistinguish, void *User, laUserRemoveFunc Remover, int ForceRecalc);
void laStopUsingDataBlock(void* HyperUserMem, laProp *prop, laPanel *p);
void laDataBlockNoLongerExists(void *HyperUserMem, laListHandle* UserList);
void la_PrintUserList(void* HyperUserMem);

void laThrowToTrashBin(void* Data, char *ContainerString);


void la_FreeProperty(laProp* p);
void la_FreePropertyContainer(laPropContainer* pc);

laSaverDummy* laGetSaverDummy(void* instance, laSubProp* p);
void laPurgeSaverDummy(void* instance, laSubProp* p);

laPropContainer *laAddPropertyContainer(const char *Identifier, const char *Name, const char *Description, uint32_t IconID, laUiDefineFunc DefaultUiDefine,
                                        int NodeSize, laContainerPostReadFunc PostRead, laContainerPostReadFunc PostReadIm, int IsHyper);
laProp* laPropContainerManageable(laPropContainer* pc, int offset_of_dummy_list);
void laPropContainerExtraFunctions(laPropContainer* pc, laContainerBeforeFreeF BeforeFree, laContainerResetF Reset, laContainerUndoTouchedF Touched, laContainerpUDFPropagateF UDFPropagate, laUiDefineFunc MenuUi);
void laContainerAnimationFunctions(laPropContainer* pc, laActionHolderVerifyF ActionHolderVerify);

const char *la_GetPropertyTypeString(int Type);

NEED_STRUCTURE(laWidget);

laProp *la_CreateProperty(laPropContainer *Container, int Type, const char *Identifier, const char *Name, const char *Description,
                          const char *Prefix, const char *Unit, laWidget* DefaultWidget, u64bit Tag);
void la_ClearDetachedProp(laPanel* p);
laProp *la_MakeDetachedProp(laPanel* p, const char *From, const char *Rename);
laProp *laAddIntProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
                         const char *Prefix, const char *Unit, int Max, int Min, int Step, int DefVal, const int *DefArr,
                         int OffsetSize, laIntGetF Get, laIntSetF Set, int ArrayLength, laArrayGetLenF GetLen,
                         laIntArraySetF SetArr, laIntArrayGetAllF GetAll, laIntArraySetAllF SetAll, laIntArraySetAllArrayF SetAllArr,
                         laIntReadF Read, laIntArrayReadAllF ReadAll,
                         u64bit Tag);

laProp *laAddFloatProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
                           const char *Prefix, const char *Unit, real Max, real Min, real Step, real DefVal, const real *DefArr,
                           int OffsetSize, laFloatGetF Get, laFloatSetF Set, int ArrayLength, laArrayGetLenF GetLen,
                           laFloatArraySetF SetArr, laFloatArrayGetAllF GetAll, laFloatArraySetAllF SetAll, laFloatArraySetAllArrayF SetAllArr,
                           laFloatReadF Read, laFloatArrayReadAllF ReadAll,
                           u64bit Tag);

laProp *laAddEnumProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
                          const char *Prefix, const char *Unit, int DefVal, const int *DefArr,
                          int OffsetSize, laEnumGetF Get, laEnumSetF Set, int ArrayLength, laArrayGetLenF GetLen,
                          laEnumArraySetF SetArr, laEnumArrayGetAllF GetAll, laEnumArraySetAllF SetAll,
                          laEnumReadF Read, laEnumArrayReadAllF ReadAll,
                          u64bit Tag);

int laAddEnumItem(laProp *p, const char *Identifier, const char *Name, const char *Description, uint32_t IconID);
int laAddEnumItemAs(laProp *p, const char *Identifier, const char *Name, const char *Description, int Index, uint32_t IconID);

laProp *laAddStringProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
                            const char *Prefix, const char *Unit, const char *DefStr,
                            int IsSafeString, int OffsetSize, laStringGetLenF GetLen, laStringGetF Get, laStringSetF Set,
                            laStringReadF Read,
                            u64bit Tag);

laProp *laAddSubGroup(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description,
                      const char *TargetId, laGetNodeTypeFunc GetType, laWidget* DefaultWidget, laUiDefineFunc DefaultUiDef,
                      int OffsetSize, laSubGetInstanceF Get, laSubGetInstanceF GetActive, laSubGetNextF GetNext, laSubSetInstanceF Set,
                      laSubGetStateF GetState, laSubSetStateF SetState, int ListHandleOffset, u64bit Tag);
void laSubGroupExtraFunctions(laProp* p, laSubUIFilterF* UiFilter, laSubSaveFilterF* SaveFilter, laSubUIThemeF* GetTheme, laSubUIGapF GetGap, laSubUICategoryF GetCategory);
void laSubGroupDetachable(laProp *SubProp, laSubTypeDetachedGet DetachedGet, laSubTypeDetachedGetNext DetachedGetNext);

laProp *laAddOperatorProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description,
                              const char *OperatorID, uint32_t IconID, laWidget* DefaultWidget);

laProp *laAddRawProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, int OffsetSize, laRawGetSizeF GetSize, laRawGetF RawGet, laRawSetF RawSet, u64bit Tag);
void laRawPropertyExtraFunctions(laProp* p, laRawMultiGetF MultiGet, laRawMultiCanGetF CanMultiGet);

//void laPropertySignal(laProp* p, int Throw, int Catch);

NEED_STRUCTURE(laBoxedTheme);

void *laGetInstance(laProp *sub, void *ThisInstance, laPropIterator *pi);
void *laGetNextInstance(laProp *sub, void *FromInstance, laPropIterator *pi);
void *laGetActiveInstanceStrict(laProp *sub, void *FromInstance);
void *laGetActiveInstance(laProp *sub, void *FromInstance, laPropIterator *pi);
void laSetActiveInstance(laProp *sub, void *FromInstance, void *Instance);
void laAppendInstance(laSubProp *sub, void *FromInstance, void *Instance);
int laGetUiState(laProp *sub, void *Instance);
laBoxedTheme* laGetUiTheme(laProp *sub, void* parent, void *Instance);
int laGetUiGap(laProp *sub, void* parent, void *Instance);
void laGetCategory(laProp *sub, void* parent, void *Instance, char* buf, char** buf_ptr);
int laCanGetState(laProp *sub);
int laCanGetTheme(laProp *sub);
int laCanGetGap(laProp *sub);
int laCanGetCategory(laProp *sub);
int laSetState(laProp *sub, void *FromInstance, void *Instance, int State);

laPropContainer *la_SetGeneralRoot(laPropContainer **GeneralRoot, const char *Identifier, const char *Name, const char *Description);

int la_GetPropFromPath(laPropPack *Self, laPropPack *Base, const char *Path, void **SpecifiedInstance);
laProp *la_GetGeneralPropFromPath(laProp *General, const char *Path);

int laValidateProperties();

void laSetRootInstance(void *root);

void la_RegisterMainUiTypes();
void la_RegisterMainThemes();
void la_RegisterInternalProps();

void la_PrintPropStructure();

laProp *la_GetGeneralProp(laProp *p);

void* laget_InstanceActiveUDF(void* instance);
void laset_InstanceUDF(void* instance, void* set);

void la_UDFAppendSharedTypePointer(char *ID, void *Pointer);

void la_AppendLinkedFile(laUDF *File);

void la_GetWorkingDirectoryInternal();
int laGetRelativeDirectory(char *FullFrom, char *FullTo, char *Result);
void laGetUDFRelativeDirectory(laUDF *From, laUDF *To, char *Result);
void laGetFullPath(char *FullFrom, char *Relative, char *Result);

laUDF *laPrepareUDF(char *FileName);
int laWriteProp(laUDF *udf, char *Path);
int laWritePropP(laUDF *udf, laPropPack *pp);
int laPackUDF(laUDF *udf, int UseInstanceList, int DoBackup);

laManagedSaveProp* laSaveProp(char* path);
void laSaveAlongside(laManagedSaveProp* parent, char* path);
void laSetThumbnailProp(char* path);
void laClearSaveProp();

int laRegisterModifications(int ReturnIfAnyMod, int ReturnIfAnyEmpty, int* rempty, int RegisterToUDF);

laUDF *laOpenUDF(char *FileName, int ReadToMemory, laUDFRegistry* ReadRegistryRef, laManagedUDF** UseManaged);
void laCloseUDF(laUDF *udf);
void laExtractProp(laUDF *udf, char* Path);
int laExtractUDF(laUDF *udf, laManagedUDF* mUDF, int Mode);

int laExtractQuickRaw(FILE* fp, char* path, uint8_t** buf, size_t* size);

int laLoadHyperResources(char* uid_search);

laUDFOwnHyperItem* laFindHyperItem(laPropContainer* pc, char* uid);
laUDFRegistry* laFindUDFRegistry(char* Path);
laUDFRegistry* laCreateUDFRegistry(char* Path);
void laClearUDFRegistries();
void laRefreshUDFRegistries();

laManagedUDF* la_FindManagedUDF(char* FileName);
laManagedUDF* la_EnsureManagedUDF(char* FileName, int PutAtTop);
void la_MakeDummyManagedUDF();
void laStopManageUDF(laManagedUDF* m);
void laClearManagedUDF();

void laSaveManagedUDF(int ModifiedOnly);

void laPropagateUDF(laPropContainer* pc, void* inst, int force);

void laSetSaveCallback(laPreSaveF PreSave, laPostSaveF PostSave);

//================== manifest

void laAddResourceFolder(char* Path);
void laRemoveResourceFolder(laResourceFolder* rf);
void la_ClearUDFRegistryAndFolders();

//================== undo

void laFreeOlderDifferences(int KeepHowMany);
void laFreeNewerDifferences();

void laPrintDBInstInfo();
void la_NoLongerRecordUndo();

void laAddRootDBInst(char* path);
void laPushDifferences(char* Description, u64bit hint);
void laRecordCustomDifferences(void* Data, laDiffCommandUndoF Undo, laDiffCommandRedoF Redo, laDiffCommandFreeF Free);
int laRecordDifferences(laPropPack* base, char* path);
int laRecordInstanceDifferences(void* instance, const char* container);
void laRecordAndPush(laPropPack* base, char* path, char* description, uint64_t hint);
void laRecordAndPushProp(laPropPack* base, char* path);
void laRecordEverythingAndPush();
void laSetDiffCallback(laDiffPushEverythingF PushEverything);

void laUndo();
void laRedo();

//======================= animation

#define LA_ANIMATION_STATUS_PAUSED   0
#define LA_ANIMATION_STATUS_PLAY_FWD 1
#define LA_ANIMATION_STATUS_PLAY_REV 2

int la_GetKeyablePropertyStorageSize(laProp* p);

void la_AnimationEvaluateActions(int ClampOffsets);
laRetargetedAction* la_AnimationGetRetargetedAction(laActionRetarget* ar, laAction* aa);

laAction* laAnimiationNewAction(laActionHolder* ah, char* Name);
laActionChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p);
laActionChannel* laAnimationEnsureFrame(laActionChannel* ac, int frame);
void laAnimationStoreKeyValue(laActionChannel* ac, laActionKey* ak);
laActionKey* laAnimationInsertKeyFrame(laAction* aa, void* hyper1, laProp* p, int* error);

void laAnimationRemoveFrame(laActionChannel* ac, laActionKey* ak);
void laAnimationRemoveChannel(laAction* aa, laActionChannel* ac);
void laAnimationRemoveAction(laAction* aa);

void* laAnimationGetRetargetedPropInstance(laProp* p, void* Instance);
void laAnimationEnsureRetarget(void* HolderInstance, laListHandle* action_list, laActionRetarget** retarget);
laActionRetarget* laAnimationCopyRetargetFrom(laActionRetarget* from_ar);
void laAnimationClearRetarget(laActionRetarget **ar_ptr);

void laAnimationSetPlayStatus(int PlayStatus);
void laAnimationSetPlayHead(real time);

int laAnimationSyncRetarget(laActionRetarget* ar, real PlayHead);
int laAnimationEvaluateRetargetedActions(laActionRetarget* ar);

void la_AnimationPreFrame();
void la_AnimationPostFrame();

int laAnimationRegisterHolderPath(const char* Path);
void laAnimationUpdateHolderList();