/*
    zdebug.c
    Copyright (C) 2011-2020 Ladislav Vaiz <ok1zia@nagano.cz>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

*/

#include <libziaint.h>

#define _CRT_SECURE_NO_WARNINGS

#include <zdebug.h>

#include <zdump.h>
#include <zgetopt.h>
#include <zmsgbox.h>
#include <zsdl.h>

#ifdef Z_HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#ifdef Z_HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef Z_HAVE_WINSOCK2_H
#include <winsock.h>
#endif

#ifdef Z_HAVE_WINDOWS_H
#include <windows.h>
#endif

#ifdef Z_HAVE_ANDROID_LOG_H
#include <android/log.h>
#endif

#include <glib.h>


static int debug_type = 0;
static FILE *debug_file = NULL;
static void (*debug_free_callback)(void) = NULL;
static void (*debug_trace_callback)(char *) = NULL;
char *debug_msg_title;

void zdebug_init(int argc, char *argv[], void (*free_callback)(void), void (*trace_callback)(char *), char *msg_title){
	char *debug_filename = NULL, *s;
//    int option_index = 0;
    int c;
/*#ifdef Z_HAVE_GETOPT_H
    static struct option long_options[] = {
        {"debug", 2, 0, 'd'},
        {0, 0, 0, 0}
    };
#endif*/


	debug_free_callback = free_callback;
	debug_trace_callback = trace_callback;
	debug_msg_title = g_strdup(msg_title);

    s = getenv("TUCNAK_DEBUG");
    if (s){
        if (strlen(s)!=0){
            debug_type=1;
            debug_filename=s;
        }else{
            debug_type=2;
        }
    } 
    
#ifdef Z_MSC
	debug_file = stderr;
#endif
  
//#ifdef Z_HAVE_GETOPT_H    
    optind = 1;  // reset scanning from begin
//	while((c = getopt_long(argc, argv, "d", long_options, &option_index)) != -1){
	while((c = getopt(argc, argv, ":dD:")) != -1){
        switch (c){
            case 'd':
            case 'D':
                if (optarg) {
                    debug_type=1;
                    debug_filename=optarg;
                }else{
                    debug_type=2;
                }
                break;
		}
	}
    optind = 1;
//#endif
    switch (debug_type){
        case 1:
            debug_file = fopen(debug_filename, "wt");
            break;
#ifndef Z_MINGW
        case 2:
            debug_file = stderr;
            break;    
#endif
    }
#ifdef Z_ANDROID
	debug_file = stderr;
#endif
/*#ifdef Z_MINGW
    debug_file = fopen("_stderr.txt", "wt");
#endif*/
    g_log_set_default_handler(z_g_log_func, NULL);
}

void zdebug_free(void){
    if (!debug_file) return;
	if (debug_msg_title) g_free(debug_msg_title);
#ifndef Z_MINGW
    if (debug_file != stderr) fclose(debug_file);
#endif
}

void z_g_log_func(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data){
    if (log_level & (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL)){
        dbg("%s: %s\n", log_domain, message);
    }else{
        error("%s: %s\n", log_domain, message);
    }
}

void z_alsa_error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...){
    va_list va;
    char *c;

    va_start(va, fmt);
    c = g_strdup_vprintf(fmt, va);
    va_end(va);
    dbg("Alsa error: %s in %s, %s:%d\n", c, function, file, line);
    g_free(c);
}

int zdebug_debug_type(void){
	return debug_type;
}


void dbg(char *fmt, ...)
{
    va_list l;
#ifndef Z_ANDROID    // all logged on android
    if (!debug_file) return;
#endif

    va_start(l, fmt);
    if (debug_file)
    {
        vfprintf(debug_file, fmt, l);
    }
#ifdef Z_MSC_MINGW
	{	
		gchar *c = g_strdup_vprintf(fmt, l);
		OutputDebugString(c);
		g_free(c);
	}
#endif
#ifdef Z_HAVE_ANDROID_LOG_H
    __android_log_vprint(ANDROID_LOG_INFO, "Tucnak"/*debug_msg_title*/, fmt, l);
#endif
    va_end(l);
}

void error(char *fmt, ...){

    va_list l;
	FILE *df = debug_file;

    //z_msgbox_error("error", "fmt='%s' debug_file=%p", fmt, debug_file);

#ifndef Z_MINGW
    if (!df) df = stderr;
#endif
    va_start(l, fmt);
//    fprintf(df, "ERROR: ");
    vfprintf(df, fmt, l);
#ifdef Z_MSC_MINGW
	{	
		gchar *c = g_strdup_vprintf(fmt, l);
		OutputDebugString(c);
		g_free(c);
	}
#endif
#ifdef Z_HAVE_ANDROID_LOG_H
    __android_log_vprint(ANDROID_LOG_ERROR, "Tucnak" /*debug_msg_title*/, fmt, l);
#endif
    va_end(l);
}


void trace(int enable, char *fmt, ...)
{
    va_list l;
	gchar *c;

    if (!enable) return;
    if (debug_file){
		va_start(l, fmt);
		vfprintf(debug_file, fmt, l);
		va_end(l);
        fprintf(debug_file, "\n");
	}
	va_start(l, fmt);
	c = g_strdup_vprintf(fmt, l);
	if (debug_trace_callback) debug_trace_callback(c);
#ifdef Z_MSC_MINGW
	OutputDebugString(c);
	OutputDebugString("\r\n");
#endif
	g_free(c);
	va_end(l);

	
}

#ifdef Z_MSC_MINGW
	       
void zinternal_error(char *file, int line, char *fmt, ...)
{
    va_list l;
	GString *gs = g_string_sized_new(100);

    va_start(l, fmt);
    g_string_printf(gs, "Internal error at %s:%d\r\n", file, line);
    g_string_append_vprintf(gs, fmt, l);
    va_end(l);
/*    g_string_append(gs, "\r\n");
    g_string_append(gs, z_dump_backtrace());*/
	z_msgbox_error(debug_msg_title ? debug_msg_title : "Libzia app", gs->str);
    g_string_free(gs, TRUE);
    exit(7301);
}

#else

void zinternal_error(char *file, int line, char *fmt, ...)
{
    va_list l;
    GString *gs = g_string_sized_new(100);
    int a;
    char *c;

	if (debug_free_callback) debug_free_callback();
    va_start(l, fmt);
#ifdef Z_ANDROID
    g_string_append_printf(gs, "INTERNAL ERROR in ");
    a = 0;
#else
    g_string_append_printf(gs, "\007\033[1mINTERNAL ERROR\033[0m in ");
    a = gs->len;
#endif
    g_string_append_printf(gs, "pid=%d at %s:%d: ", getpid(), file, line);

    // g_string_append_vprintf is not on Etch
    c = g_strdup_vprintf(fmt, l);
    g_string_append(gs, c);
    g_free(c);
    va_end(l);

/*    g_string_append(gs, "\nBacktrace:\n");
    g_string_append(gs, z_dump_backtrace(gs, NULL, NULL, 0));
    g_string_append(gs, "\n");*/
    error("%s", gs->str);

    if (zsdl_get()){
        g_string_erase(gs, 0, a);
        z_msgbox_error(debug_msg_title ? debug_msg_title : "Libzia app", "%s", gs->str);
    }
    sleep(0);
    zforce_dump();
    exit(7302);
}
#endif

void zhexdump(void *buf, size_t len, const char *desc){
    size_t i;
    for (i = 0; i < len; i++){
        dbg("%02X ", (unsigned char)((unsigned char*)buf)[i]);
    }
    if (desc != NULL) dbg(" %s\n", desc);

}
