/*
Copyright (c) 2007 Taco Hoekwater <taco@latex.org>

This file is part of luatex.

luatex 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 2 of the License, or
(at your option) any later version.

luatex 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 luatex; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

This is llanglib.c 
*/

#include "luatex-api.h"
#include <ptexlib.h>

#include "nodes.h"

#define LANG_METATABLE "luatex.lang"

#define check_islang(L,b) (struct tex_language **)luaL_checkudata(L,b,LANG_METATABLE)

extern halfword *check_isnode (lua_State *L, int ud) ;


static int 
lang_new (lua_State *L) {
  struct tex_language **lang;
  if (lua_gettop(L)==0) {
    lang = lua_newuserdata(L, sizeof(struct tex_language *));
    *lang = new_language();
    if (!*lang) {
      lua_pushstring(L,"lang.new(): no room for a new language");
      return lua_error(L);
    }
  } else {
    lang = lua_newuserdata(L, sizeof(struct tex_language *));
    *lang = get_language(lua_tonumber(L,1));
  }
  luaL_getmetatable(L,LANG_METATABLE);
  lua_setmetatable(L,-2);
  return 1;
}

static int 
lang_id (lua_State *L) {
  struct tex_language **lang_ptr;
  lang_ptr = check_islang(L,1);
  lua_pushnumber(L,(*lang_ptr)->id);
  return 1;
}

static int 
lang_patterns (lua_State *L) {
  struct tex_language **lang_ptr;
  lang_ptr = check_islang(L,1);
  if (lua_gettop(L)!=1) {
	if (!lua_isstring(L,2)) {
	  lua_pushstring(L,"lang.patterns(): argument should be a string");
	  return lua_error(L);
	}
	load_patterns(*lang_ptr, (unsigned char *)lua_tostring(L,2));
	return 0;
  } else {
	if ((*lang_ptr)->patterns!=NULL) {
	  lua_pushstring(L,(char *)hnj_serialize((*lang_ptr)->patterns));
	} else {
	  lua_pushnil(L);
	}
	return 1;
  }
}

static int 
lang_clear_patterns (lua_State *L) {
  struct tex_language **lang_ptr;
  lang_ptr = check_islang(L,1);
  clear_patterns(*lang_ptr);
  return 0;
}


static int 
lang_hyphenation (lua_State *L) {
  struct tex_language **lang_ptr;
  lang_ptr = check_islang(L,1);
  if (lua_gettop(L)!=1) {
	if(!lua_isstring(L,2)) {
	  lua_pushstring(L,"lang.hyphenation(): argument should be a string");
	  return lua_error(L);
	}
	load_hyphenation(*lang_ptr,(unsigned char *)lua_tostring(L,2));
	return 0;
  } else {
	if ((*lang_ptr)->exceptions!=0) {
	  lua_pushstring(L,exception_strings(*lang_ptr));
	} else {
	  lua_pushnil(L);
	}
	return 1;
  }
}

static int 
lang_pre_hyphen_char (lua_State *L) {
  struct tex_language **lang_ptr;
  lang_ptr = check_islang(L,1);
  if (lua_gettop(L)!=1) {
	if(!lua_isnumber(L,2)) {
	  lua_pushstring(L,"lang.prehyphenchar(): argument should be a character number");
	  return lua_error(L);
	}
	(*lang_ptr)->pre_hyphen_char = lua_tonumber(L,2);
	return 0;
  } else {
	lua_pushnumber(L,(*lang_ptr)->pre_hyphen_char);
	return 1;
  }
}

static int 
lang_post_hyphen_char (lua_State *L) {
  struct tex_language **lang_ptr;
  lang_ptr = check_islang(L,1);
  if (lua_gettop(L)!=1) {
	if(!lua_isnumber(L,2)) {
	  lua_pushstring(L,"lang.posthyphenchar(): argument should be a character number");
	  return lua_error(L);
	}
	(*lang_ptr)->post_hyphen_char = lua_tonumber(L,2);
	return 0;
  } else {
	lua_pushnumber(L,(*lang_ptr)->post_hyphen_char);
	return 1;
  }
}

static int 
lang_clear_hyphenation (lua_State *L) {
  struct tex_language **lang_ptr;
  lang_ptr = check_islang(L,1);
  clear_hyphenation(*lang_ptr);
  return 0;
}


static int 
do_lang_clean (lua_State *L) {
  char *cleaned;
  if (!lua_isstring(L,1)) {
    lua_pushstring(L,"lang.clean(): argument should be a string");
    return lua_error(L);
  }
  (void)clean_hyphenation((char *)lua_tostring(L,1),&cleaned);
  lua_pushstring(L,cleaned);
  return 1;
}

static int 
do_lang_hyphenate (lua_State *L) {
  halfword *h,*t;
  h = check_isnode(L,1);
  if (lua_isuserdata(L,2)) {
	t = check_isnode(L,2);
	lua_pop(L,1);
  } else {
	t = h;
	while (vlink(*t)!=null)
	  *t = vlink(*t);
  }
  hnj_hyphenation(*h,*t);
  lua_pushboolean(L,1);
  return 1;
}


static const struct luaL_reg langlib_d [] = {
  {"clear_patterns",    lang_clear_patterns},
  {"clear_hyphenation", lang_clear_hyphenation},
  {"patterns",          lang_patterns},
  {"hyphenation",       lang_hyphenation},
  {"prehyphenchar",     lang_pre_hyphen_char}, 
  {"posthyphenchar",    lang_post_hyphen_char},
  {"id",                lang_id},
  {NULL, NULL}  /* sentinel */
};


static const struct luaL_reg langlib[] = {
  {"clear_patterns",    lang_clear_patterns},
  {"clear_hyphenation", lang_clear_hyphenation},
  {"patterns",          lang_patterns},
  {"hyphenation",       lang_hyphenation},
  {"prehyphenchar",     lang_pre_hyphen_char}, 
  {"posthyphenchar",    lang_post_hyphen_char},
  {"id",                lang_id},
  {"clean",             do_lang_clean},
  {"hyphenate",         do_lang_hyphenate},
  {"new",               lang_new},
  {NULL, NULL}                /* sentinel */
};


int 
luaopen_lang (lua_State *L) {
  luaL_newmetatable(L,LANG_METATABLE);
  lua_pushvalue(L, -1);  /* push metatable */
  lua_setfield(L, -2, "__index");  /* metatable.__index = metatable */
  luaL_register(L, NULL, langlib_d);  /* dict methods */
  luaL_register(L, "lang", langlib);
  return 1;
}

