// livetext.c
// weed plugin
// (c) G. Finch (salsaman) 2009 - 2012
//
// released under the GNU GPL 3 or later
// see file COPYING or www.gnu.org for details


#ifdef HAVE_SYSTEM_WEED
#include <weed/weed.h>
#include <weed/weed-palettes.h>
#include <weed/weed-effects.h>
#else
#include "../../libweed/weed.h"
#include "../../libweed/weed-palettes.h"
#include "../../libweed/weed-effects.h"
#endif

///////////////////////////////////////////////////////////////////

static int num_versions=2; // number of different weed api versions supported
static int api_versions[]={131,100}; // array of weed api versions supported in plugin, in order of preference (most preferred first)

static int package_version=2; // version of this package

//////////////////////////////////////////////////////////////////

#ifdef HAVE_SYSTEM_WEED_PLUGIN_UTILS
#include <weed/weed-plugin.h> // optional
#else
#include "../../libweed/weed-plugin.h" // optional
#endif

#include "weed-utils-code.c" // optional
#include "weed-plugin-utils.c" // optional

/////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <string.h>

typedef struct {
  char *fontname;
  int width;
  int nglyphs;
  uint16_t *fonttable;
} font_table_t;


typedef struct {
  int red;
  int green;
  int blue;
} rgb_t;


/////////////////////////////////////////////


static int get_hex_digit (char *d) {
  char c[2];
  c[0]=*d;
  c[1]=0;

  if (!strcmp (c,"a")||!strcmp (c,"A")) return 10;
  if (!strcmp (c,"b")||!strcmp (c,"B")) return 11;
  if (!strcmp (c,"c")||!strcmp (c,"C")) return 12;
  if (!strcmp (c,"d")||!strcmp (c,"D")) return 13;
  if (!strcmp (c,"e")||!strcmp (c,"E")) return 14;
  if (!strcmp (c,"f")||!strcmp (c,"F")) return 15;
  return(atoi (c));
}


#define NFONTMAPS 2

static char *font_maps[NFONTMAPS];
static font_table_t font_tables[NFONTMAPS];


static void make_font_tables(void) {
  // font_map format is "font_name|glyphbitwidth|bitmap of glyphs"
  // glyph height is always 8 bits

  // this can be expanded by increasing NFONTMAPS

  font_maps[0]="ANSI|8|0000183C3C3C18181800181800000000006666662400000000000000000000000000006C6CFE6C6C6CFE6C6C0000000018187CC6C2C07C060686C67C1818000000000000C2C60C183060C686000000000000386C6C3876DCCCCCCC76000000000030303060000000000000000000000000000C18303030303030180C00000000000030180C0C0C0C0C0C1830000000000000000000663CFF3C66000000000000000000000018187E181800000000000000000000000000000018181830000000000000000000007E0000000000000000000000000000000000001818000000000000000002060C183060C0800000000000007CC6C6CEDEF6E6C6C67C0000000000001838781818181818187E0000000000007CC6060C183060C0C6FE0000000000007CC606063C060606C67C0000000000000C1C3C6CCCFE0C0C0C1E000000000000FEC0C0C0FC060606C67C0000000000003860C0C0FCC6C6C6C67C000000000000FEC606060C18303030300000000000007CC6C6C67CC6C6C6C67C0000000000007CC6C6C67E0606060C78000000000000000018180000001818000000000000000000181800000018183000000000000000060C18306030180C060000000000000000007E00007E000000000000000000006030180C060C1830600000000000007CC6C60C1818180018180000000000007CC6C6C6DEDEDEDCC07C00000000000010386CC6C6FEC6C6C6C6000000000000FC6666667C66666666FC0000000000003C66C2C0C0C0C0C2663C000000000000F86C6666666666666CF8000000000000FE6662687868606266FE000000000000FE6662687868606060F00000000000003C66C2C0C0DEC6C6663A000000000000C6C6C6C6FEC6C6C6C6C60000000000003C18181818181818183C0000000000001E0C0C0C0C0CCCCCCC78000000000000E666666C78786C6666E6000000000000F06060606060606266FE000000000000C3E7FFFFDBC3C3C3C3C3000000000000C6E6F6FEDECEC6C6C6C60000000000007CC6C6C6C6C6C6C6C67C000000000000FC6666667C60606060F00000000000007CC6C6C6C6C6C6D6DE7C0C0E00000000FC6666667C6C666666E60000000000007CC6C660380C06C6C67C000000000000FFDB991818181818183C000000000000C6C6C6C6C6C6C6C6C67C000000000000C3C3C3C3C3C3C3663C18000000000000C3C3C3C3C3DBDBFF6666000000000000C3C3663C18183C66C3C3000000000000C3C3C3663C181818183C000000000000FFC3860C183060C1C3FF0000000000003C30303030303030303C0000000000000080C0E070381C0E06020000000000003C0C0C0C0C0C0C0C0C3C0000000010386CC600000000000000000000000000000000000000000000000000FF0000303018000000000000000000000000000000000000780C7CCCCCCC76000000000000E06060786C666666667C0000000000000000007CC6C0C0C0C67C0000000000001C0C0C3C6CCCCCCCCC760000000000000000007CC6FEC0C0C67C000000000000386C6460F060606060F000000000000000000076CCCCCCCCCC7C0CCC78000000E060606C7666666666E60000000000001818003818181818183C0000000000000606000E06060606060666663C000000E06060666C78786C66E60000000000003818181818181818183C000000000000000000E6FFDBDBDBDBDB000000000000000000DC6666666666660000000000000000007CC6C6C6C6C67C000000000000000000DC66666666667C6060F000000000000076CCCCCCCCCC7C0C0C1E000000000000DC7666606060F00000000000000000007CC660380CC67C000000000000103030FC30303030361C000000000000000000CCCCCCCCCCCC76000000000000000000C3C3C3C3663C18000000000000000000C3C3C3DBDBFF66000000000000000000C3663C183C66C3000000000000000000C6C6C6C6C6C67E060CF8000000000000FECC183060C6FE0000000000000E18181870181818180E00000000000018181818001818181818000000000000701818180E181818187000000000000076DC0000000000000000000000000000000010386CC6C6C6FE0000000000";
  

  // hex encoded font map - Hiragana
  font_maps[1]="Hiragana|16|[encoded data, 10720 characters]";


 int i,j,k;
 int nglyphs;
 size_t len;

  for (k=0;k<NFONTMAPS;k++) {
    len=strcspn(font_maps[k],"|");
    font_tables[k].fontname=weed_malloc(len+1);
    weed_memcpy(font_tables[k].fontname,font_maps[k],len);
    weed_memset(font_tables[k].fontname+len,0,1);
    font_maps[k]+=len+1;
    font_tables[k].width=atoi(font_maps[k]);
    len=strcspn(font_maps[k],"|");
    font_maps[k]+=len+1;
    nglyphs=strlen(font_maps[k])/4/font_tables[k].width;
    font_tables[k].nglyphs=++nglyphs;
    font_tables[k].fonttable=weed_malloc(32*nglyphs);

    for (i=0;i<nglyphs*16;i+=16) {
      for (j=0;j<16;j++) {
	if (i==0) font_tables[k].fonttable[j]=0; // make sure we have a space
	else {
	  if (font_tables[k].width==16) {
	    font_tables[k].fonttable[i+j]=((get_hex_digit(&font_maps[k][(i-16+j)*4])<<12)+(get_hex_digit(&font_maps[k][(i-16+j)*4+1])<<8)+(get_hex_digit(&font_maps[k][(i-16+j)*4+2])<<4)+(get_hex_digit(&font_maps[k][(i-16+j)*4+3])));
	  }
	  else {
	    font_tables[k].fonttable[i+j]=((get_hex_digit(&font_maps[k][(i-16+j)*2])<<4)+(get_hex_digit(&font_maps[k][(i-16+j)*2+1])));
	  }
	}
      }
    }
  }
}



static inline void fill_line(int fontwidth, unsigned char *dst, unsigned short fontrow, int type, rgb_t *fg, rgb_t *bg) {
  register int i;

  for (i=fontwidth-1;i>=0;i--) {
    switch (type) {
    case 1:
      // fg and bg
      if (fontrow&(1<<i)) {
	dst[0]=fg->red;
	dst[1]=fg->green;
	dst[2]=fg->blue;
      }
      else {
	dst[0]=bg->red;
	dst[1]=bg->green;
	dst[2]=bg->blue;
      }
      break;
    case 0:
      // fg only
      if (fontrow&(1<<i)) {
	dst[0]=fg->red;
	dst[1]=fg->green;
	dst[2]=fg->blue;
      }
      break;
    case 2:
      // bg only
      if (!(fontrow&(1<<i))) {
	dst[0]=bg->red;
	dst[1]=bg->green;
	dst[2]=bg->blue;
      }
      break;
    }
    dst+=3;
  }
}


static inline void fill_block(int fontnum, unsigned char *dst, int drow, int glyph, int type, rgb_t *fg, rgb_t *bg) {
  // we will fill a 8x16 block of pixels in dst with a map of a character
  register int i;


  glyph-=32;

  if (glyph<0||glyph>=font_tables[fontnum].nglyphs) return;

  for (i=0;i<16;i++) {
    fill_line(font_tables[fontnum].width,dst,font_tables[fontnum].fonttable[glyph*16+i],type,fg,bg);
    dst+=drow;
  }
}




int get_xpos(char *str, int width, int cent) {
  register int i;
  int linelen=0,res;

  if (cent==WEED_FALSE) return 0;

  for (i=0;str[i]!=0;i++) {
    if (!strncmp(str+i,"\n",1)) {
      break;
    }
    linelen++;
  }

  res=(width-linelen)/2;

  return res<0?0:res;
}





int get_ypos(char *str, int height, int rise) {
  register int i;
  int res=height-1;

  if (rise==WEED_FALSE) return 0;

  for (i=0;str[i]!=0;i++) {
    if (!strncmp(str+i,"\n",1)) res--;
  }

  return res;
}










/////////////////////////////////////////////////////////////


int livetext_process (weed_plant_t *inst, weed_timecode_t timestamp) {
  int error;
  //unsigned int irow16,orow16;
  //unsigned int startx,starty,endx;

  register int i;

  //int j;

  int mode;
  char *text;

  int fontnum;

  weed_plant_t *out_channel=weed_get_plantptr_value(inst,"out_channels",&error);
  unsigned char *dst=weed_get_voidptr_value(out_channel,"pixel_data",&error);

  int width=weed_get_int_value(out_channel,"width",&error),widthx,widthz;
  int height=weed_get_int_value(out_channel,"height",&error),heightx=height>>4;

  int orowstride=weed_get_int_value(out_channel,"rowstrides",&error);

  weed_plant_t **in_params=weed_get_plantptr_array(inst,"in_parameters",&error);
  int ofill;

  int palette=weed_get_int_value(out_channel,"current_palette",&error);

  int pbits=3;

  int xpos,ypos,offs;

  rgb_t *fg,*bg;

  int cent,rise;

  weed_plant_t *in_channel=NULL;
  unsigned char *src;
  int irowstride=0;

  if (weed_plant_has_leaf(inst,"in_channels")) {
    in_channel=weed_get_plantptr_value(inst,"in_channels",&error);
    src=weed_get_voidptr_value(in_channel,"pixel_data",&error);
    irowstride=weed_get_int_value(in_channel,"rowstrides",&error);
  }
  else src=dst;


  if (palette==WEED_PALETTE_RGBA32||palette==WEED_PALETTE_BGRA32) pbits=4;

  text=weed_get_string_value(in_params[0],"value",&error);
  mode=weed_get_int_value(in_params[1],"value",&error);
  fontnum=weed_get_int_value(in_params[2],"value",&error);
  
  fg=(rgb_t *)weed_get_int_array(in_params[3],"value",&error);
  bg=(rgb_t *)weed_get_int_array(in_params[4],"value",&error);

  cent=weed_get_boolean_value(in_params[5],"value",&error);
  rise=weed_get_boolean_value(in_params[6],"value",&error);

  if (palette==WEED_PALETTE_BGR24||palette==WEED_PALETTE_BGRA32) {
    int tmp=fg->red;
    fg->red=fg->blue;
    fg->blue=tmp;

    tmp=bg->red;
    bg->red=bg->blue;
    bg->blue=tmp;
  }


  weed_free(in_params); // must weed free because we got an array

  widthx=width*pbits;

  widthz=width/font_tables[fontnum].width;

  ofill=orowstride-widthx;

  pbits*=font_tables[fontnum].width;

  if (src!=dst) {
    for (i=0;i<height;i++) {
      weed_memcpy(&dst[i*orowstride],&src[i*irowstride],widthx);
      if (ofill>0) weed_memset(&dst[i*orowstride+widthx],0,ofill);
    }
  }

  xpos=get_xpos(text,widthz,cent);
  ypos=get_ypos(text,heightx,rise);

  for (i=0;i<strlen(text);i++) {
    if (!strncmp(text+i,"\n",1)) {
      xpos=get_xpos(text+i+1,widthz,cent);
      ypos++;
    }
    else {
      if (xpos>=0&&xpos<widthz&&ypos>=0&&ypos<heightx) {
	offs=ypos*orowstride*16+xpos*pbits;
	fill_block(fontnum,&dst[offs],orowstride,(int)text[i],mode,fg,bg);
      }
      xpos++;
    }
  }

  weed_free(text);
  weed_free(fg);
  weed_free(bg);

  return WEED_NO_ERROR;
}




weed_plant_t *weed_setup (weed_bootstrap_f weed_boot) {
  weed_plant_t *plugin_info=weed_plugin_info_init(weed_boot,num_versions,api_versions);
  weed_plant_t **clone1,**clone2;

  if (plugin_info!=NULL) {
    const char *modes[]={"foreground only","foreground and background","background only",NULL};
    int palette_list[]={WEED_PALETTE_BGR24,WEED_PALETTE_RGB24,WEED_PALETTE_RGBA32,WEED_PALETTE_BGRA32,WEED_PALETTE_END};
    weed_plant_t *in_chantmpls[]={weed_channel_template_init("in channel 0",0,palette_list),NULL};
    weed_plant_t *out_chantmpls[]={weed_channel_template_init("out channel 0",WEED_CHANNEL_CAN_DO_INPLACE,palette_list),NULL};
    weed_plant_t *in_params[8],*pgui;
    weed_plant_t *filter_class;

    const char *fonts[NFONTMAPS+1];
    int i;

    make_font_tables();

    for (i=0;i<NFONTMAPS;i++) {
      fonts[i]=font_tables[i].fontname;
    }
    fonts[i]=NULL;

    in_params[0]=weed_text_init("text","_Text","");
    in_params[1]=weed_string_list_init("mode","Colour _mode",0,modes);
    in_params[2]=weed_string_list_init("font","_Font",0,fonts);
    in_params[3]=weed_colRGBi_init("foreground","_Foreground",255,255,255);
    in_params[4]=weed_colRGBi_init("background","_Background",0,0,0);
    in_params[5]=weed_switch_init("center","_Center text",WEED_TRUE);
    in_params[6]=weed_switch_init("rising","_Rising text",WEED_TRUE);
    in_params[7]=NULL;
    
    pgui=weed_parameter_template_get_gui(in_params[0]);
    weed_set_int_value(pgui,"maxchars",65536);

    filter_class=weed_filter_class_init("livetext","salsaman",1,0,NULL,&livetext_process,NULL,in_chantmpls,out_chantmpls,in_params,NULL);

    weed_plugin_info_add_filter_class (plugin_info,filter_class);

    filter_class=weed_filter_class_init("livetext_generator","salsaman",1,0,NULL,&livetext_process,NULL,NULL,(clone1=weed_clone_plants(out_chantmpls)),(clone2=weed_clone_plants(in_params)),NULL);
    weed_free(clone1);
    weed_free(clone2);

    weed_plugin_info_add_filter_class (plugin_info,filter_class);
    weed_set_double_value(filter_class,"target_fps",25.); // set reasonable default fps

    weed_set_int_value(plugin_info,"version",package_version);

  }

  return plugin_info;
}



void weed_desetup(void) {
  int k;
  for (k=0;k<NFONTMAPS;k++) {
    weed_free(font_tables[k].fontname);
    weed_free(font_tables[k].fonttable);
  }

}
