/* AbiWord
 * Copyright (C) 1998,1999 AbiSource, Inc.
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */


// TODO: still getting some artifacts when doing highligh/replacements

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

#include "ut_string.h"
#include "ut_assert.h"
#include "ut_debugmsg.h"

#include "xap_App.h"
#include "xap_QNXApp.h"
#include "xap_QNXFrame.h"

#include "ap_Strings.h"
#include "ap_Dialog_Id.h"
#include "ap_Dialog_Spell.h"
#include "ap_QNXDialog_Spell.h"
#include "ut_qnxHelper.h"


XAP_Dialog * AP_QNXDialog_Spell::static_constructor(XAP_DialogFactory * pFactory, XAP_Dialog_Id id)
{
   AP_QNXDialog_Spell * p = new AP_QNXDialog_Spell(pFactory,id);
   return p;
}

AP_QNXDialog_Spell::AP_QNXDialog_Spell(XAP_DialogFactory * pDlgFactory, XAP_Dialog_Id id)
  : AP_Dialog_Spell(pDlgFactory,id)
{
}

AP_QNXDialog_Spell::~AP_QNXDialog_Spell(void)
{
}

/************************************************************/
void AP_QNXDialog_Spell::runModal(XAP_Frame * pFrame)
{
	// class the base class method to initialize some basic xp stuff
	AP_Dialog_Spell::runModal(pFrame);
   
	m_bCancelled = false;
	bool bRes = nextMisspelledWord();

	// To center the dialog, we need the frame of its parent.
	XAP_QNXFrame * pQNXFrame = static_cast<XAP_QNXFrame *>(pFrame);
   	UT_ASSERT(pQNXFrame);
      
   	// Get the Window of the parent frame
   	PtWidget_t * parentWindow = pQNXFrame->getTopLevelWindow();
   	UT_ASSERT(parentWindow);
	PtSetParentWidget(parentWindow);
    
	if (bRes) { // we need to prepare the dialog
      
      	PtWidget_t * mainWindow = _constructWindow();
      	UT_ASSERT(mainWindow);
      
      	// Populate the window's data items
      	_populateWindowData();
      
		UT_QNXCenterWindow(parentWindow, mainWindow);
		UT_QNXBlockWidget(parentWindow, 1);

		PtRealizeWidget(mainWindow);
      
     	// now loop while there are still misspelled words
     	while (bRes) {
	 
	 		// show word in main window
	 		makeWordVisible();
	 
	 		// update dialog with new misspelled word info/suggestions
	 		_showMisspelledWord();
	 
			int count;
			count = PtModalStart();
			done = 0;
			while(!done) {
				PtProcessEvent();
			}
			PtModalEnd(MODAL_END_ARG(count));
		 
			for (int i = 0; i < m_Suggestions.count; i++) {
				FREEP(m_Suggestions.word[i]);
			}
	 		FREEP(m_Suggestions.word);
	 		FREEP(m_Suggestions.score);
	 		m_Suggestions.count = 0;
	 
	 		if (m_bCancelled) {
				break;
			}
	 
			// get the next unknown word
			bRes = nextMisspelledWord();
		}
      
		_storeWindowData();
      
		UT_QNXBlockWidget(parentWindow, 0);
		PtDestroyWidget(mainWindow);
	}
}

/**********************************************************/
static int s_change_clicked(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(widget && dlg);
   dlg->event_Change();
	return Pt_CONTINUE;
}

static int s_change_all_clicked(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(widget && dlg);
   dlg->event_ChangeAll();
	return Pt_CONTINUE;
}

static int s_ignore_clicked(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(widget && dlg);
   dlg->event_Ignore();
	return Pt_CONTINUE;
}

static int s_ignore_all_clicked(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(widget && dlg);
   dlg->event_IgnoreAll();
	return Pt_CONTINUE;
}

static int s_add_to_dict_clicked(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(widget && dlg);
   dlg->event_AddToDict();
	return Pt_CONTINUE;
}

static int s_cancel_clicked(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(widget && dlg);
   dlg->event_Cancel();
	return Pt_CONTINUE;
}

static int s_suggestion_selected(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(widget && dlg);
	PtListCallback_t   *list = (PtListCallback_t *)info->cbdata;
   dlg->event_SuggestionSelected(list->item_pos, list->item);
	return Pt_CONTINUE;
}

static int s_replacement_changed(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(widget && dlg);
   dlg->event_ReplacementChanged();
	return Pt_CONTINUE;
}

static int s_delete_clicked(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 
{
	AP_QNXDialog_Spell *dlg = (AP_QNXDialog_Spell *)data;
   UT_ASSERT(dlg);
   dlg->event_Cancel();
	return Pt_CONTINUE;
}
/********************************************************************/

PtWidget_t * AP_QNXDialog_Spell::_constructWindow(void)
{
   PtWidget_t *windowSpell;
   
   PtWidget_t *label1;
   PtWidget_t *textWord;
   PtWidget_t *label2;
   PtWidget_t *entryChange;
   PtWidget_t *clistSuggestions;
   PtWidget_t *buttonChange;
   PtWidget_t *buttonChangeAll;
   PtWidget_t *buttonIgnore;
   PtWidget_t *buttonIgnoreAll;
   PtWidget_t *buttonAddToDict;
   PtWidget_t *buttonCancel;
	PtArg_t  args[10];
	int    n;
	PhArea_t area;

   const XAP_StringSet * pSS = m_pApp->getStringSet();
   XML_Char * unixstr = NULL;      // used for conversions

	n = 0;
    PtSetArg(&args[n++], Pt_ARG_WINDOW_TITLE, pSS->getValue(AP_STRING_ID_DLG_Spell_SpellTitle), 0);
    PtSetArg(&args[n++], Pt_ARG_WINDOW_RENDER_FLAGS, 0, ABI_MODAL_WINDOW_RENDER_FLAGS);
    PtSetArg(&args[n++], Pt_ARG_WINDOW_MANAGED_FLAGS, 0, ABI_MODAL_WINDOW_MANAGE_FLAGS);
	windowSpell = PtCreateWidget(PtWindow, NULL, n, args);
	PtAddCallback(windowSpell, Pt_CB_WINDOW_CLOSING, s_delete_clicked, this);
   
#define TEXT_WIDTH   200
#define LABEL_HEIGHT  10
#define TEXTBOX_HEIGHT  100
#define H_SPACER     15
#define V_SPACER   	 15


	n = 0;
   UT_XML_cloneNoAmpersands(unixstr, pSS->getValue(AP_STRING_ID_DLG_Spell_UnknownWord));
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, unixstr, 0);
	area.pos.x = area.pos.y = V_SPACER;
	area.size.w = TEXT_WIDTH; area.size.h = LABEL_HEIGHT;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0);
   	label1 = PtCreateWidget(PtLabel, windowSpell, n, args);

	//Add the multi-text snippet around the word we are writing ....
	n = 0;
	area.pos.y += area.size.h + V_SPACER;
	area.size.h = TEXTBOX_HEIGHT;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0);
	PtSetArg(&args[n++], Pt_ARG_TEXT_FLAGS, 0, Pt_EDITABLE);
    textWord = PtCreateWidget(PtMultiText, windowSpell, n, args);

   // ignore button set
	n = 0;
	area.pos.x += area.size.w + H_SPACER;
	area.size.w = ABI_DEFAULT_BUTTON_WIDTH;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0);
	PtSetArg(&args[n++], Pt_ARG_GROUP_ORIENTATION, Pt_GROUP_VERTICAL, 0);
	PtSetArg(&args[n++], Pt_ARG_GROUP_FLAGS, 
			 Pt_GROUP_EQUAL_SIZE_HORIZONTAL, 
			 Pt_GROUP_EQUAL_SIZE_HORIZONTAL);
   PtWidget_t * vboxIgnoreButtons = PtCreateWidget(PtGroup, windowSpell, n, args);
   
   UT_XML_cloneNoAmpersands(unixstr, pSS->getValue(AP_STRING_ID_DLG_Spell_Ignore));
	n = 0;
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, unixstr, 0);
	PtSetArg(&args[n++], Pt_ARG_WIDTH, ABI_DEFAULT_BUTTON_WIDTH, 0);
   buttonIgnore = PtCreateWidget(PtButton, vboxIgnoreButtons, n, args);
	PtAddCallback(buttonIgnore, Pt_CB_ACTIVATE, s_ignore_clicked, this);
   
   UT_XML_cloneNoAmpersands(unixstr, pSS->getValue(AP_STRING_ID_DLG_Spell_IgnoreAll));
	n = 0;
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, unixstr, 0);
	PtSetArg(&args[n++], Pt_ARG_WIDTH, ABI_DEFAULT_BUTTON_WIDTH, 0);
   buttonIgnoreAll = PtCreateWidget(PtButton, vboxIgnoreButtons, n, args);
	PtAddCallback(buttonIgnoreAll, Pt_CB_ACTIVATE, s_ignore_all_clicked, this);
   
   UT_XML_cloneNoAmpersands(unixstr, pSS->getValue(AP_STRING_ID_DLG_Spell_AddToDict));
	n = 0;
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, unixstr, 0);
	PtSetArg(&args[n++], Pt_ARG_WIDTH, ABI_DEFAULT_BUTTON_WIDTH, 0);
   buttonAddToDict = PtCreateWidget(PtButton, vboxIgnoreButtons, n, args);
	PtAddCallback(buttonAddToDict, Pt_CB_ACTIVATE, s_add_to_dict_clicked, this);

   // suggestion half
   UT_XML_cloneNoAmpersands(unixstr, pSS->getValue(AP_STRING_ID_DLG_Spell_ChangeTo));
	n = 0;
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, unixstr, 0);
	area.pos.x = H_SPACER; 
	area.pos.y = V_SPACER + LABEL_HEIGHT + V_SPACER + TEXTBOX_HEIGHT + V_SPACER; 
	area.size.w = TEXT_WIDTH / 3;
	area.size.h = LABEL_HEIGHT;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0);
   label2 = PtCreateWidget(PtLabel, windowSpell, n, args);

	n = 0;
	area.pos.x += area.size.w + H_SPACER;
	area.size.w = (TEXT_WIDTH / 3) * 2 - H_SPACER;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0);
   entryChange = PtCreateWidget(PtText, windowSpell, n, args);
	PtAddCallback(entryChange, Pt_CB_TEXT_CHANGED, s_replacement_changed, this);
	//We should call change when we hit return
	//PtAddCallback(entryChange, Pt_CB_ACTIVATE, s_change_clicked, this);

	n = 0;
	area.pos.x = H_SPACER;
	area.pos.y += area.size.h + V_SPACER;
	area.size.w = TEXT_WIDTH;
	area.size.h = TEXTBOX_HEIGHT;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0);
   clistSuggestions = PtCreateWidget(PtList, windowSpell, n, args);
	//We should call the "activate" on double click
	//PtAddCallback(clistSuggestions, Pt_CB_ACTIVATE, s_change_clicked, this);
	PtAddCallback(clistSuggestions, Pt_CB_SELECTION, s_suggestion_selected, this);

   
   // change buttons
	n = 0;
	area.pos.x += area.size.w + H_SPACER;
	area.size.w = ABI_DEFAULT_BUTTON_WIDTH;
	PtSetArg(&args[n++], Pt_ARG_AREA, &area, 0);
	PtSetArg(&args[n++], Pt_ARG_GROUP_ORIENTATION, Pt_GROUP_VERTICAL, 0);
	PtSetArg(&args[n++], Pt_ARG_GROUP_FLAGS, 
			 Pt_GROUP_EQUAL_SIZE_HORIZONTAL, 
			 Pt_GROUP_EQUAL_SIZE_HORIZONTAL);
   PtWidget_t * vboxChangeButtons = PtCreateWidget(PtGroup, windowSpell, n, args);

   UT_XML_cloneNoAmpersands(unixstr, pSS->getValue(AP_STRING_ID_DLG_Spell_Change));
	n = 0;
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, unixstr, 0);
	PtSetArg(&args[n++], Pt_ARG_WIDTH, ABI_DEFAULT_BUTTON_WIDTH, 0);
   buttonChange = PtCreateWidget(PtButton, vboxChangeButtons, n, args);
	PtAddCallback(buttonChange, Pt_CB_ACTIVATE, s_change_clicked, this);
   
   UT_XML_cloneNoAmpersands(unixstr, pSS->getValue(AP_STRING_ID_DLG_Spell_ChangeAll));
	n = 0;
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, unixstr, 0);
	PtSetArg(&args[n++], Pt_ARG_WIDTH, ABI_DEFAULT_BUTTON_WIDTH, 0);
   buttonChangeAll = PtCreateWidget(PtButton, vboxChangeButtons, n, args);
	PtAddCallback(buttonChangeAll, Pt_CB_ACTIVATE, s_change_all_clicked, this);
   
	n = 0;
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, pSS->getValue(XAP_STRING_ID_DLG_Cancel), 0);
	PtSetArg(&args[n++], Pt_ARG_WIDTH, ABI_DEFAULT_BUTTON_WIDTH, 0);
   buttonCancel = PtCreateWidget(PtButton, vboxChangeButtons, n, args);
	PtAddCallback(buttonCancel, Pt_CB_ACTIVATE, s_cancel_clicked, this);
   
   // update member variables with the important widgets 
   // that we'll interact with later
   
   m_buttonChange = buttonChange;
   m_buttonChangeAll = buttonChangeAll;
   m_buttonIgnore = buttonIgnore;
   m_buttonIgnoreAll = buttonIgnoreAll;
   m_buttonAddToDict = buttonAddToDict;
   m_buttonCancel = buttonCancel;
   
   m_textWord = textWord;
   m_entryChange = entryChange;
   m_clistSuggestions = clistSuggestions;
   m_windowMain = windowSpell;
   
   return windowSpell;
}

static char *get_text_string(PtWidget_t *w) {
	char *text;
	PtGetResource(w, Pt_ARG_TEXT_STRING, &text, 0);
	return text;
}

static void set_text_string(PtWidget_t *w, char *str) {
	PtSetResource(w, Pt_ARG_TEXT_STRING, str, 0);
}

void AP_QNXDialog_Spell::_showMisspelledWord(void)
{                                
	PtArg_t args[10];
	int 	n;

	n = 0;
	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, 0, 0);
	PtSetResources(m_textWord, n, args);
   
   UT_UCSChar *p;
   char 		*str;
   int		   len;

   // insert start of sentence
   p = _getPreWord();
   str = _convertToMB(p);
   len = mbstrlen(str, 0, NULL);
   FREEP(p);
	PtMultiTextAttributes_t attrs;
	memset(&attrs, 0, sizeof(attrs));
	attrs.text_color = Pg_BLACK;
	PtMultiTextModifyText(m_textWord, 	/* Widget */
						  0, 0,			/* start, end positions */
						  -1,			/* insert position (end of buffer) */
						  str,	/* text to insert */
						  len,			/* length of text */
						  &attrs,			/* Attributes (use default) */
						  Pt_MT_TEXT_COLOR);		    /* Flags on which attrs to use */				
   FREEP(str);
   
   // insert misspelled word (in highlight color)
   p = _getCurrentWord();
   str = _convertToMB(p);
   len = mbstrlen(str, 0, NULL);
   FREEP(p);
	attrs.text_color = Pg_RED;
  	PtMultiTextModifyText(m_textWord, 	/* Widget */
						  0, 0,			/* start, end positions */
						  -1,			/* insert position (end of buffer) */
						  str,			/* text to insert */
						  len,			/* length of text */
						  &attrs,		/* Attributes */
						  Pt_MT_TEXT_COLOR);   /* Flags on which attrs to use */				
   
   FREEP(str);

   // insert end of sentence
   p = _getPostWord();
   str = _convertToMB(p);
   len = mbstrlen(str, 0, NULL);
   FREEP(p);
	attrs.text_color = Pg_BLACK;
  	PtMultiTextModifyText(m_textWord, 	/* Widget */
						  0, 0,			/* start, end positions */
						  -1,			/* insert position (end of buffer) */
						  str,			/* text to insert */
						  len,			/* length of text */
						  &attrs,		/* Attributes */
						  Pt_MT_TEXT_COLOR);   /* Flags on which attrs to use */				
   FREEP(str);
    
   // TODO: set scroll position so misspelled word is centered


   char *suggest[2] = {NULL, NULL};

   PtListDeleteAllItems(m_clistSuggestions); 
   for (int i = 0; i < m_Suggestions.count; i++) {
	  suggest[0] = _convertToMB((UT_UCSChar *)m_Suggestions.word[i]);
      PtListAddItems(m_clistSuggestions, (const char **)suggest, 1, 0);
	  if (i==0) {
		set_text_string(m_entryChange, suggest[0]);
	  }
	  FREEP(suggest[0]);
   }
  
   if (!m_Suggestions.count) {

      const XAP_StringSet * pSS = m_pApp->getStringSet();
      UT_XML_cloneNoAmpersands(suggest[0], pSS->getValue(AP_STRING_ID_DLG_Spell_NoSuggestions));

      PtListAddItems(m_clistSuggestions, (const char **)&suggest[0], 1, 0);
      FREEP(suggest[0]);
	  	n = 0;
	  	PtSetArg(&args[n++], Pt_ARG_FLAGS, Pt_BLOCKED, Pt_BLOCKED);
		PtSetResources(m_clistSuggestions, n, args);

		n = 0;
      	PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, NULL, 0);
		PtSetResources(m_entryChange, n, args);

      	m_iSelectedRow = -1;
   } else {
      	// select first on the list; signal handler should update our entry box
		PtListSelectPos(m_clistSuggestions, 1);
   }
   
}

void AP_QNXDialog_Spell::_populateWindowData(void)
{
   // TODO: initialize list of user dictionaries
}

void AP_QNXDialog_Spell::_storeWindowData(void)
{
   // TODO: anything to store?
}

/*************************************************************/

void AP_QNXDialog_Spell::event_Change()
{
	UT_UCSChar * replace = NULL;

   	if (m_iSelectedRow != -1) {
		replace = (UT_UCSChar*) m_Suggestions.word[m_iSelectedRow];
		changeWordWith(replace);
	}
	else {
		char *text = get_text_string(m_entryChange);
		replace = _convertFromMB(text);
		if (!UT_UCS_strlen(replace)) {
		   FREEP(replace);
		   return;
		}
		changeWordWith(replace);
		FREEP(replace);
   	}
	done = 1;
}

void AP_QNXDialog_Spell::event_ChangeAll()
{
	UT_UCSChar * replace = NULL;

	if (m_iSelectedRow != -1) {
		replace = (UT_UCSChar*) m_Suggestions.word[m_iSelectedRow];
		addChangeAll(replace);
		changeWordWith(replace);
	}
	else {
		char *text = get_text_string(m_entryChange);
		replace = _convertFromMB(text);
		if (!UT_UCS_strlen(replace)) {
			FREEP(replace);
			return;
		}
		addChangeAll(replace);
		changeWordWith(replace);
		FREEP(replace);
	}
	done = 1;
}

void AP_QNXDialog_Spell::event_Ignore()
{
   	ignoreWord();
	done = 1;
}

void AP_QNXDialog_Spell::event_IgnoreAll()
{
   	addIgnoreAll();
   	ignoreWord();
	done = 1;
}

void AP_QNXDialog_Spell::event_AddToDict()
{
	addToDict();
	ignoreWord();
	done = 1;
}

void AP_QNXDialog_Spell::event_Cancel()
{
   	if (!done++) {
		m_bCancelled = true;
	}
}

//This is called when the user clicks an item in the list ...
void AP_QNXDialog_Spell::event_SuggestionSelected(int index, char *newreplacement)
{

   if (!newreplacement) return;

	m_iSelectedRow = index - 1;
	set_text_string(m_entryChange, newreplacement); 

	//Set the suggestion text ....
   UT_ASSERT(newreplacement);
}

void AP_QNXDialog_Spell::event_ReplacementChanged()
{
	printf("Replacement changed \n");

	char * modtext = get_text_string(m_entryChange);
	UT_ASSERT(modtext);

	int index = PtListItemPos(m_clistSuggestions, modtext);
  	if (index != 0) {
		m_iSelectedRow = index -1;
		PtListSelectPos(m_clistSuggestions, index); 
		//PtListGotoPos(m_clistSuggestions, index);
	}
	else {
		if (m_iSelectedRow > 0) {
			PtListUnselectPos(m_clistSuggestions, m_iSelectedRow + 1);
		}
		//PtListGotoPos(m_clistSuggestions, 0);
   		m_iSelectedRow = -1;
	}
}


// Photon uses multibyte strings for i18n
// these functions convert from wide (UCS) to MB and back

// TODO: these are probably generally useful functions,
// TODO: but I don't know about xp support for them.

// make a multibyte encoded version of a string
char * AP_QNXDialog_Spell::_convertToMB(UT_UCSChar *wword)
{
#if 0
	int    len;
	char   *buffer;

	len = UT_UCS_strlen(wword);
	buffer = new char[(len + 1) * 3];	//Be very pessimistic about size
	wcstombs(buffer, (wchar_t *)wword, len*3);	
	return buffer;
#else
	char *word = (char *) malloc (UT_UCS_strlen(wword)*3);
	UT_UCS_strcpy_to_char(word,wword);
	return word;
#endif
}

// make a wide string from a multibyte string
UT_UCSChar * AP_QNXDialog_Spell::_convertFromMB(char *word)
{
#if 0
	int 		len;
	UT_UCSChar *buffer;

	len = mbstrlen(word, 0, NULL);
	buffer = new UT_UCSChar[(len + 1) * 2];
	mbstowcs((wchar_t *)buffer, word, len);	
	return buffer;
#else
	UT_UCSChar *wword = (UT_UCSChar *) malloc (strlen(word)*2);
	UT_UCS_strcpy_char(wword,word);
	return wword;
#endif
}
