eu_core = {}
eu_core.ffi = require("ffi")
eu_core.eulib = require("euapi")
eu_core.euapi = eu_core.ffi.load(eu_core.ffi.os == "Windows" and "euapi.dll")

eu_core.ffi.cdef[[

typedef struct tagRECT
{
    long left;
    long top;
    long right;
    long bottom;
}RECT;

typedef struct tagACCEL
{
    unsigned short fVirt;
    unsigned short key;
    unsigned short cmd;
}ACCEL;

typedef struct _print_set
{
    int header;
    int footer;
    int color_mode;
    int zoom;
    RECT rect;
}print_set;

typedef struct _columnctl_set
{
    int initnum;
    int increase;
    int repeater;
    int leading;
    int format;
}columnctl_set;

typedef struct _titlebar_set
{
    bool icon;
    bool name;
    bool path;
}titlebar_set;

typedef struct _caret_set
{
    int blink;
    int width;
    uint32_t rgb;
}caret_set;

typedef struct _bookmark_set
{
    bool visable;
    int  shape;
    uint32_t argb;
}bookmark_set;

typedef struct _brace_set
{
    bool matching;
    bool autoc;
    uint32_t rgb;
}brace_set;

typedef struct _calltip_set
{
    bool enable;
    uint32_t rgb;
}calltip_set;

typedef struct _complete_set
{
    bool enable;
    int  characters;
    int  snippet;
}complete_set;

typedef struct _eue_toolbar
{
    int imsg;
    int icmd;
    char isvg[4096];
}eue_toolbar;

typedef struct _upgrade_set
{
    bool enable;
    int  flags;
    int  msg_id;
    uint64_t last_check;
    char url[260];
}upgrade_set;

typedef struct _openai_set
{
    bool think;
    bool stream;
    int  max_tokens;
    char key[64];
    char model[64];
    char base[128];
    char setting[1024];
}openai_set;

typedef struct _customize_set
{
    bool hide;
    char name[64];
    char path[260];
    char param[260];
    int  micon;
    int  posid;
    uintptr_t hbmp;
}customize_set;

struct eu_config
{
    int new_file_eol;
    int new_file_enc;
    
    bool m_ident;
    char window_theme[64];
    bool m_fullscreen;
    bool m_menubar;
    int m_toolbar;
    bool m_statusbar;
    bool m_linenumber;

    uint32_t last_flags;
    uint32_t history_mask;
    
    bool m_indentation;
    int tab_width;
    bool tab2spaces;
    bool light_fold;
    bool line_mode;
    bool m_ftree_show;

    int file_tree_width;
    int sym_list_width;
    int sym_tree_width;
    int sidebar_width;
    int document_map_width;
    int result_edit_height;
    int result_list_height;
    int file_recent_number;
    int scroll_to_cursor;
    int inter_reserved_0;
    int inter_reserved_1;
    int inter_reserved_2;
    
    bool block_fold;
    bool m_tab_tip;
    bool m_tab_split;
    
    int m_code_hint;
    int m_close_way;
    int m_close_draw;
    int m_new_way;
    int m_tab_active;
    int m_quality;
    int m_render;
    int  m_upfile;
    int  m_up_notify;
    int  m_doc_restrict;

    bool m_undo_selection;
    bool m_light_str;
    bool m_write_copy;
    bool m_session;
    bool m_exit;
    bool m_instance;
    bool m_logging;
    char m_placement[1024];
    char m_language[64];
    bookmark_set eu_bookmark;
    brace_set eu_brace;
    calltip_set eu_calltip;
    complete_set eu_complete;
    print_set eu_print;
    columnctl_set eu_column;
    titlebar_set eu_titlebar;
    bool m_hyperlink;
    int m_limit;
    upgrade_set upgrade;
    openai_set openai;
    char sep_copy[260];
    char m_path[260];
    char editor[260];
    char m_reserved_0[260];
    char m_reserved_1[260];
    char m_actions[100][260];
    customize_set m_customize[32];
};

struct styleclass
{
    char font[32];
    int fontsize;
    uint32_t color;
    uint32_t bgcolor;
    int bold;
};

struct styletheme
{
    struct styleclass linenumber;
    struct styleclass foldmargin;

    struct styleclass text;
    struct styleclass caretline;
    struct styleclass indicator;

    struct styleclass keywords0;
    struct styleclass keywords1;
    struct styleclass string;
    struct styleclass character;
    struct styleclass number;
    struct styleclass operators;
    struct styleclass preprocessor;
    struct styleclass comment;
    struct styleclass commentline;
    struct styleclass commentdoc;

    struct styleclass tags;
    struct styleclass unknowtags;
    struct styleclass attributes;
    struct styleclass unknowattributes;
    struct styleclass entities;
    struct styleclass tagends;
    struct styleclass cdata;
    struct styleclass phpsection;
    struct styleclass aspsection;
    struct styleclass xmlsection;
    
    struct styleclass activetab;
    struct styleclass caret;
    struct styleclass symbolic;
    struct styleclass hyperlink;
    struct styleclass results;
    struct styleclass bracesection;
    struct styleclass nchistory;
    struct styleclass dochistory;
    struct styleclass whitechar;
};

struct eu_theme
{
    char pathfile[260];
    char name[64];
    struct styletheme item;
};

struct rb_node
{
    uintptr_t rb_parent_color;
    struct rb_node *rb_right;
    struct rb_node *rb_left;
};

struct rb_root
{
    struct rb_node *rb_node;
};

struct opt_format
{
    bool no_c;
    bool no_p;
    bool no_f;
    bool no_x;
    bool no_t;
    bool no_d;
    bool no_a;
};

typedef struct rb_root eutype_t;
typedef int (*init_before_ptr)(void *pnode);
typedef int (*init_after_ptr)(void *pnode);
typedef int (*parse_header_ptr)(void *pnode);
typedef int (*add_ptr)(void *pnode, void *lpnotify);
typedef int (*key_ptr)(void *pnode, intptr_t wParam, intptr_t lParam);
typedef int (*reload_list_ptr)(void *pnode);
typedef int (*click_list_ptr)(void *pnode);
typedef int (*reload_tree_ptr)(void *pnode);
typedef int (*click_tree_ptr)(void *pnode);

typedef struct _doc_styles
{
    int type[200];
    uint32_t fgcolor[200];
    uint32_t bkcolor[200];
    uint32_t mask;
} doc_styles;

typedef struct _doc_comments
{
    const char *line;
    const char *block;
    bool initialized;
} doc_comments;

typedef struct _doc_fonts
{
    const char *font0;
    const char *font1;
    const char *font2;
    int size;
} doc_fonts;

typedef struct _snippet_t
{
    intptr_t start;
    intptr_t end;
    char name[64];
    char comment[64];
    char parameter[8];
    char body[2048];
} snippet_t;

typedef struct _doc_data
{
    int doc_type;                             // 文档类型编号,自行添加请从末尾数字开始递增
    const char *filetypename;                 // 文档类型名称
    const char *extname;                      // 文档扩展名
    const char *filedesc;                     // 文档类型描述
    const char *snippet;                      // 文档的代码片段文件所在
    int tab_width;                            // tab键宽度, default = 0, 跟随主配置
    int tab_convert_spaces;                   // tab键是否转换为空格, default = -1: 跟随主配置, 0: false, 1: true
    init_before_ptr fn_init_before;           // 回调函数, 在文档初始化前运行
    init_after_ptr fn_init_after;             // 回调函数, 在文档初始化后运行
    parse_header_ptr fn_parse_header;         // 回调函数, 分析文件头, 用于sql
    key_ptr fn_keydown;                       // 回调函数, 当编辑器内按下某键
    key_ptr fn_keyup;                         // 回调函数, 当编辑器内释放某键
    add_ptr fn_on_char;                       // 回调函数, 当编辑器输入字符
    reload_list_ptr fn_reload_symlist;        // 回调函数, 右侧边栏list控件初始化
    click_list_ptr fn_click_symlist;          // 回调函数, 右侧边栏list控件被点击
    reload_tree_ptr fn_reload_symtree;        // 回调函数, 右侧边栏tree控件初始化
    click_tree_ptr fn_click_symtree;          // 回调函数, 右侧边栏tree控件被点击
    snippet_t *ptrv;                          // 解析后的代码片段关键字
    const char *keywords0;                    // 需要高亮的关键字, 分6类高亮着色
    const char *keywords1;
    const char *keywords2;
    const char *keywords3;
    const char *keywords4;
    const char *keywords5;
    const char *reqular_exp;                  // 根据此正则表达式初始化list控件
    eutype_t acshow_tree;                     // 自动补全hash表
    eutype_t ctshow_tree;                     // 函数提示hash表
    doc_styles style;                         // 文档关键字类型与高亮颜色
    doc_comments comment;                     // 文档注释
    doc_fonts font_list;                      // 文档字体
} doctype_t;

// for tinyexpr
typedef struct te_expr
{
    int type;
    union {double value; const double *bound; const void *function;};
    void *parameters[1];
} te_expr;

typedef struct te_variable
{
    const char *name;
    const void *address;
    int type;
    void *context;
} te_variable;

// 获取配置文件指针
bool eu_config_ptr(struct eu_config *pconfig);
bool eu_theme_ptr(struct eu_theme *ptheme);
bool eu_accel_ptr(ACCEL *paccel);
bool eu_toolbar_ptr(eue_toolbar *pdata, int num);
bool eu_exist_path(const char *path);
bool eu_xml_pretty(void *ptr, struct opt_format *opt);

// crt 函数
void free(void *);
void *malloc(size_t len);
size_t strlen(const char *);
char *_fullpath(char *buf, const char *path, size_t maxlen);

// windows api
int CloseHandle(void *);
int GetWindowTextW(void *hwnd, wchar_t *str, int count);
intptr_t SendMessageW(void *hwnd, uint32_t msg, intptr_t wp, intptr_t lp);

// euapi 函数
double eu_te_eval(const te_expr *n);
double eu_te_interp(const char *expression, int *error);
void eu_te_print(const te_expr *n);
void eu_te_free(te_expr *n);
te_expr *eu_te_compile(const char *expression, const te_variable *variables, int var_count, int *error);
void eu_lua_calltip(const char *pstr);

char *eu_utf16_utf8(const wchar_t *utf16, size_t *out_len);
char *eu_utf16_mbcs(int codepage, const wchar_t *utf16, size_t *out_len);
wchar_t *eu_mbcs_utf16(int codepage, const char *ansi, size_t *out_len);
char *eu_mbcs_utf8(int codepage, const char *ansi, size_t *out_len);
wchar_t *eu_utf8_utf16(const char *utf8, size_t *out_len);
char *eu_utf8_mbcs(int codepage, const char *utf8, size_t *out_len);
char *eu_strdup_content(const int index);
char *eu_strdup_line(const int t, const intptr_t line_number);
char *eu_strdup_select(const int t);
char *eu_strdup_content(const int index);
char *eu_strdup_range(const int t, const intptr_t start, const intptr_t end);
char *eu_sci_range(const void *p, const intptr_t start, const intptr_t end);
char *eu_file_path(const int t);
char *eu_file_name(const int t);
int eu_file_close(const int t, const int mode);
int eu_file_open(const wchar_t *path);
int eu_msgbox(void *w, const wchar_t *txt, const wchar_t *cap, uint32_t type);
intptr_t eu_file_size(const int t);
intptr_t eu_end_positon(const int t);
intptr_t eu_line_start_positon(const int t, const intptr_t line);
intptr_t eu_line_end_positon(const int t, const intptr_t line);
/* 保存所有文件 */
void eu_file_save_all(void);
/* 编辑器主窗口句柄 */
void *eu_module_hwnd(void);
/* 启动其他进程, *o保存了pid */
void *eu_new_process(const wchar_t *wcmd, const wchar_t *param, const wchar_t *pcd, int flags, uint32_t *o);
/* 获取void *的值 */
intptr_t eu_value(void *p);
/* 是否运行在Linux/Wine */
bool eu_under_wine(void);
/* 文件是否在环境变量路径中 */
bool eu_which(const char *path, char **pout);
/* 获取系统版本 */
const uint32_t eu_win10_or_later(void);

int eu_tab_focus_index(void);
int eu_tab_last_index(void);
void eu_tab_select(const int index);

int  eu_command_save(const int t);
void eu_command_talk(const int t, const char *str);
void eu_command_jump(const int t, const intptr_t line);
void eu_command_launch(const int t);
void eu_command_which(const char *str);
void eu_command_run(const int t, const char *str, const bool fnclose);
/* 重设文件编码 */
bool eu_command_reload(const int t, const char *enc);
bool eu_command_convert(const int t, const char *enc);
/* 保存文件 */
bool eu_command_saveas(const int t, const char *path, const int mode);
bool eu_command_xsave(const int t);
bool eu_command_search(const int t, const char *key, const uint32_t opt);
bool eu_command_replace(const int t, const char *key, const char *replace, const intptr_t n1, const intptr_t n2, const uint32_t opt);
bool eu_command_tabs_hint(const char *str, const bool focus);

// all doctype callbacks
bool eu_init_calltip_tree(doctype_t *p, const char *key, const char *val);
bool eu_init_completed_tree(doctype_t *p, const char *val);
intptr_t eu_sci_call(const int t, const int m, const intptr_t w, const intptr_t l);
intptr_t eu_sci_cmd(const void *p, const int m, const intptr_t w, const intptr_t l);

/* 默认的 init_before_ptr 回调函数入口 */
int on_doc_init_list(void *pnode);
int on_doc_init_tree(void *pnode);
int on_doc_init_result(void *pnode);
int on_doc_init_list_sh(void *pnode);

/* 默认的 init_after_ptr 回调函数入口 */
int on_doc_init_after_cpp(void *pnode);
int on_doc_init_after_cs(void *pnode);
int on_doc_init_after_java(void *pnode);
int on_doc_init_after_go(void *pnode);
int on_doc_init_after_swift(void *pnode);
int on_doc_init_after_sql(void *pnode);
int on_doc_init_after_redis(void *pnode);
int on_doc_init_after_python(void *pnode);
int on_doc_init_after_lua(void *pnode);
int on_doc_init_after_perl(void *pnode);
int on_doc_init_after_rust(void *pnode);
int on_doc_init_after_ruby(void *pnode);
int on_doc_init_after_lisp(void *pnode);
int on_doc_init_after_asm(void *pnode);
int on_doc_init_after_cobol(void *pnode);
int on_doc_init_after_html(void *pnode);
int on_doc_init_after_css(void *pnode);
int on_doc_init_after_js(void *pnode);
int on_doc_init_after_xml(void *pnode);
int on_doc_init_after_json(void *pnode);
int on_doc_init_after_yaml(void *pnode);
int on_doc_init_after_makefile(void *pnode);
int on_doc_init_after_cmake(void *pnode);
int on_doc_init_after_log(void *pnode);
int on_doc_init_after_nim(void *pnode);
int on_doc_init_after_shell_sh(void *pnode);
int on_doc_init_after_shell_batch(void *pnode);
int on_doc_init_after_shell_power(void *pnode);
int on_doc_init_after_properties(void *pnode);
int on_doc_init_after_diff(void *pnode);

/* 默认的 key_ptr 回调函数入口 */
int on_doc_keydown_jmp(void *pnode, intptr_t wParam, intptr_t lParam);
int on_doc_keydown_sql(void *pnode, intptr_t wParam, intptr_t lParam);
int on_doc_keydown_redis(void *pnode, intptr_t wParam, intptr_t lParam);
int on_doc_keyup_general(void *pnode, intptr_t wParam, intptr_t lParam);
int on_doc_keyup_general_sh(void *, intptr_t wParam, intptr_t lParam);

/* 默认的 add_ptr 回调函数入口 */
int on_doc_identation(void *pnode, void *lpnotify);
int on_doc_cpp_like(void *pnode, void *lpnotify);
int on_doc_sql_like(void *pnode, void *lpnotify);
int on_doc_redis_like(void *pnode, void *lpnotify);
int on_doc_html_like(void *pnode, void *lpnotify);
int on_doc_xml_like(void *pnode, void *lpnotify);
int on_doc_css_like(void *pnode, void *lpnotify);
int on_doc_json_like(void *pnode, void *lpnotify);
int on_doc_makefile_like(void *pnode, void *lpnotify);
int on_doc_cmake_like(void *pnode, void *lpnotify);
int on_doc_text_like(void *pnode, void *lpnotify);
int on_doc_general_like(void *pnode, void *lpnotify);

/* 默认的 reload_list_ptr,reload_tree_ptr 回调函数入口 */
int on_doc_reload_list_reqular(void *pnode);
int on_doc_reload_list_sh(void *pnode);
int on_doc_reload_tree_xml(void *pnode);
int on_doc_reload_tree_json(void *pnode);
int on_doc_reload_tree_sql(void *pnode);
int on_doc_reload_tree_redis(void *pnode);
int on_doc_click_list_jmp(void *pnode);
int on_doc_click_list_jump_sh(void *pnode);
int on_doc_click_tree_sql(void *pnode);
int on_doc_click_tree_json(void *pnode);
int on_doc_click_tree_xml(void *pnode);
int on_doc_click_tree_redis(void *pnode);

/* lua脚本接口支持, 对各类关键字着色 */
int on_doc_init_after_scilexer(void *p, const char *name);
void on_doc_enable_foldline(void *p);
void on_doc_default_light(void *p, int lex, intptr_t bg_rgb, intptr_t bk_rgb, const bool force);
void on_doc_keyword_light(void *p, int lex, int index, intptr_t rgb);
void on_doc_function_light(void *p, int lex, int index, intptr_t rgb);
void on_doc_preprocessor_light(void *p, int lex, int index, intptr_t rgb);
void on_doc_marcro_light(void *p, int lex, int index, intptr_t rgb);
void on_doc_variable_light(void *p, int lex, intptr_t rgb);
void on_doc_string_light(void *p, int lex, intptr_t rgb);
void on_doc_operator_light(void **pnode, int lex, intptr_t rgb);
void on_doc_char_light(void *p, int lex, intptr_t rgb);
void on_doc_number_light(void *p, int lex, intptr_t rgb);
void on_doc_special_light(void *p, int lex, intptr_t rgb);
void on_doc_send_light(void *p, int lex, int index, intptr_t rgb);
void on_doc_tags_light(void *p, int lex, intptr_t rgb);
void on_doc_comment_light(void *, int lex, intptr_t rgb);
void on_doc_commentblock_light(void *, int lex, intptr_t rgb);
void on_doc_commentdoc_light(void *, int lex, intptr_t rgb);

/* 配置文件重置函数 */
void eu_reset_main_mask(void);
void eu_reset_sqls_mask(void);
void eu_reset_docs_mask(void);
void eu_reset_accs_mask(void);
void eu_reset_snip_mask(void);
void eu_reset_theme_mask(void);

]]

function eu_core.process_path()
    return eu_core.eulib.lprocessdir()
end

function eu_core.script_path()
    return eu_core.eulib.lconfdir()
end

function eu_core.mkdir(path)
    return eu_core.eulib.lmkdir(path)
end

function eu_core.file_exists(path)
   local f=io.open(path,"r")
   if f~=nil then io.close(f) return true else return false end
end

function eu_core.table_is_empty(t)
    if t == nil then return true end
    return _G.next(t) == nil
end

function eu_core.enum(tbl)
    local i = 0
    if tbl == nil or type(tbl) ~= "table" then 
        return nil
    end 
    tbl.__index = tbl 
    tbl.__newindex = function() 
        print("can not modify enum")
    end
    for key,value in pairs(tbl) do i=i+1 end
    if (i >= 2) then i=i-2 end
    return setmetatable({}, tbl),i
end

function eu_core.save_file(filename, buffer)
    local f = assert(io.open(filename, 'wb+'))
    io.output(f)
    io.write(buffer)
    io.close(f)
end

function eu_core.strncat(dest, src, num)
    return eu_core.ffi.C.strncat(dest, src, num)
end

return eu_core
