
#include "stdio.h"
#include "stdarg.h"
#include "debug.h"
#include "string.h"
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "errno.h"
#include "pthread.h"
#include "lambda.h"

#define CONSOLEBUF_SIZE 1024




typedef struct{
  int inited;
  int print_context;
  pthread_mutex_t mutex; /* 互斥锁定义 */
  dbg_dev *dev;
}self_def;

static self_def g_data;

lambda_use


static dbg_dev g_dev_default = {
  .init = lambda(int() {
    return 0;
  }),
  .write = lambda(int(const uint8_t * data,size_t len) {
    size_t rb;
    rb=fwrite(data,sizeof(uint8_t),len,stdout);
    return (int)rb;
  })
};




int debug_init(dbg_dev *dev)
{
  self_def *self=&g_data;
  if(dev==NULL){
    dev=&g_dev_default;
  }
  if(self->inited==0)
  {
    pthread_mutex_init(&self->mutex, NULL);
    self->dev=dev;
    self->dev->init();
    self->dev->write((const uint8_t *)"\r\n",2);
    self->inited = 1;
    debug_print_context(0);
    DBG_LOG("debug inited.\r\n");
  }
  return 0;
}

void debug_print_context(int enable) {
  g_data.print_context = enable;
}


void debug_log(const char *file,const char *fun,int line,int level,const char *fmt, ...)
{
  self_def *self=&g_data;
  if(self->inited==0) return;
  va_list args;
  size_t length;
  static char log_buf[CONSOLEBUF_SIZE];
  static const char *level_str[]={"[info] ","[log] ","[warn] ","[err] "};
  static int level_str_len[]={7,6,7,6};
  if(level<DBG_LEVEL_INFO||level>DBG_LEVEL_ERR) return;
  pthread_mutex_lock(&self->mutex);
  memcpy(log_buf,level_str[level],level_str_len[level]);
  length = level_str_len[level];
  if (self->print_context) {
    length += sprintf(log_buf + length, "%s:%d|%s| ", file, line, fun);
  }

  va_start(args, fmt);
  length += vsnprintf(log_buf + length, CONSOLEBUF_SIZE - length - 3, fmt, args);
  va_end(args);
  if (length > CONSOLEBUF_SIZE - 3)
    length = CONSOLEBUF_SIZE - 3;
  if(log_buf[length-1]!='\n'){
    memcpy(&log_buf[length],"\n",1);
    length+=1;
  }
  log_buf[length]=0;
  self->dev->write((const uint8_t *)log_buf,length);
  pthread_mutex_unlock(&self->mutex);

}


