/*
<dictionary>
  <entry>
     <ita>Attezione: premere OK per cancellare</ita>
     <eng>Atension: pres ochei to dilit</eng>
     <src>ba1.exe</src>
     <max>40</max>
  </entry>
</dictionary>
*/
#include <xvt.h>

#include <config.h>
#include <diction.h>
#include <netsock.h>
#include <scanner.h>

///////////////////////////////////////////////////////////
// Utility di conversione
///////////////////////////////////////////////////////////

TString& txt2xml(const TString& str)
{
  TString& tmp = get_tmp_string();
  for (int i = 0; str[i]; i++)
  {
    if (str[i] < ' ' || str[i] > 'z' || strchr("&<>/", str[i]) != NULL)
    {
      TString8 code;
      code.format("&#%X;", (int)(unsigned char)(str[i]));
      tmp << code;
    }
    else
      tmp << str[i];
  }
  return tmp;
}

TString& xml2txt(const TString& str)
{
  TString& tmp = get_tmp_string();
  for (int i = 0; str[i]; i++)
  {
    if (str[i] == '&' && str[i+1] == '#')
    {
      i += 2;
      const int semicolon = str.find(';', i);
      if (semicolon > 0)
      {
        int n;
        sscanf(str.sub(i, semicolon), "%X", &n);
        tmp << char(n & 0xFF);
        i = semicolon;
      }
    }
    else
      tmp << str[i];
  }
  return tmp;
}

///////////////////////////////////////////////////////////
// TTraduttore
///////////////////////////////////////////////////////////

class TTraduttore : public TCache
{
	TString _str;
  TSocketClient _client;
	CONNID _connection;
   
protected:
	virtual TObject* key2obj(const char* key);

public:
	bool active() const { return _connection != 0; }
	const char* translate(const char* sentence);
	TTraduttore();
	virtual ~TTraduttore();
};

TObject* TTraduttore::key2obj(const char* key)
{
  const char* const prefix = "<sentence>";
  const char* const posfix = "</sentence>";

	_str.cut(0);
	_str << "<m:Translate>\n"
			 << prefix << txt2xml(key) << posfix << '\n'
	     << "</m:Translate>\n";

	if (_client.HttpSoap(_connection, _str))
	{
		_str.cut(0);
		size_t size;
		const TFixed_string buf((const char*)_client.GetBuffer(size));
		int start = buf.find("<sentence");
		if (start > 0)
			start = buf.find('>', start+1)+1;
		if (start > 0)
		{
			const int stop = buf.find('<', start);
			if (stop > 0)
				_str = xml2txt(buf.sub(start, stop));
		}
    // _client.ReleaseBuffer();  // Non perdiamo tempo in 'ste cose
	}
	else
		return NULL;

	return _str.dup();
}

const char* TTraduttore::translate(const char* sentence)
{
	if (sentence && *sentence && active())
	{
		for (int i = 0; sentence[i]; i++)  
		{
			if (isalpha(sentence[i]))
			{
				TString* trans = (TString*)objptr(sentence);
				if (trans != NULL && trans->not_empty())
					return (const char*) *trans;
				break;
			}
		}
	}
	return sentence;
}

TTraduttore::TTraduttore() : _connection(0)
{
  TConfig ini(CONFIG_INSTALL, "Server");
  const TString& server = ini.get("Dictionary");
  if (server.not_empty())
	  _connection = _client.QueryConnection("3883", server);
}

TTraduttore::~TTraduttore()
{
	// Autoclose connection
}

static TTraduttore* _DevotoOli = NULL;

const char* dictionary_translate(const char* sentence)
{
 if (_DevotoOli == NULL)
    _DevotoOli = new TTraduttore;
  return _DevotoOli->translate(sentence);
}

const char* dictionary_translate_macro(const char* sentence)
{
#ifdef WIN32
	if (memcmp(sentence, TO_BE_TRANSLATED, 4) == 0)
    sentence = dictionary_translate(sentence+4);
#else
  sentence = dictionary_translate(sentence);
#endif
	return sentence;
}

char strip_accelerator(TString& str)
{
	char tilde= '\0';
	for (int i = 0; str[i]; i++)
	{
		if (str[i] == '~' || str[i] == '&')
		{
			tilde = str[i+1];
			str.strip("~&");
		  break;
		}
	}
	return tilde;
}

void restore_accelerator(TString& str, char acc, char tilde)
{
	if (acc > ' ')
	{
		int newtilde = 0;
		for (int m = 0; str[m]; m++)
		{
			if (toupper(str[m]) == acc)
			{
				newtilde = m;
				break;
			}
		}
		const char s[2] = { tilde, '\0' };
		str.insert(s, newtilde);
	}
}

// len - Effect
//  -1 - No length limit
//   0 - Exactly same lenght as original
//  >0 - Maximum specified length
const char* dictionary_translate_prompt(const char* prompt, int maxlen)
{
	if (prompt && *prompt && dictionary_active())
	{
		TString& str = get_tmp_string();
		str = prompt;

    int prefixlen = 0;
		if (str[0] == '@')
      prefixlen = 2; else
		if (str[0] == '$')
      prefixlen = 6;
		TString8 prefix;
    if (prefixlen > 0)
    {
      prefix = str.left(prefixlen);
      str = str.mid(prefixlen);    
    }
		
		const char matilde = strip_accelerator(str);  // Ricorda tasto rapido
    
		const int oldlen = str.len(); // Memorizza vecchia lunghezza
		str = dictionary_translate(str);
		if (maxlen >= 0)
		{
			const int limit = maxlen == 0 ? oldlen : maxlen;
			if (str.len() > limit)
			{
				// Abbrevio all'ultima consonante
				int i;
				
				for (i = limit-2; i > 0; i--)
				{
					if (strchr("aeiou", str[i]) == NULL)
					{
						str.cut(i+1);
						str << '.';
						break;
					}
				}
				if (i <= 0)
					str.cut(limit);
			}
			if (maxlen == 0 && str.len() < limit)
				str.left_just(limit);
		}
		restore_accelerator(str, matilde, '~');
		str.insert(prefix);

		return str;
	}
	return prompt;
}

const char* dictionary_translate_macro_prompt(const char* sentence, int maxlen)
{
#ifdef WIN32
	if (memcmp(sentence, TO_BE_TRANSLATED, 4) == 0)
    sentence = dictionary_translate_prompt(sentence+4, maxlen);
#else
  sentence = dictionary_translate_prompt(sentence, maxlen);
#endif
	return sentence;
}

const char* dictionary_translate_header(const char* head)
{
	if (head && *head && dictionary_active())
	{
		const TFixed_string str(head);
		const int at = str.rfind('@');
		if (at >= 0)
		{
			TString& tmp = get_tmp_string();
  		tmp = dictionary_translate(str.left(at));
			tmp << str.mid(at);
			return tmp;
		}
		
		if (str.ends_with(" "))
			return dictionary_translate_prompt(head);
		
		return dictionary_translate(head);
	}
	return head;
}

const char* dictionary_translate_macro_header(const char* head)
{
#ifdef WIN32
	if (memcmp(head, TO_BE_TRANSLATED, 4) == 0)
    head = dictionary_translate_header(head+4);
#else    
  head = dictionary_translate_header(head);
#endif
	return head;
}

const char* dictionary_translate_menu_item(const char* text)
{
	TString& str = get_tmp_string();
	str = text;
	const char matilde = strip_accelerator(str);

	TString16 posfix;
  int start = str.find('\t');
	if (start < 0)
		start = str.find("...");
	if (start > 0)
	{
		posfix = str.mid(start);
	  str.cut(start);
	}

	const char* newtext = dictionary_translate(str);
	if (str != newtext)
	{
    str = newtext;
		restore_accelerator(str, matilde, '&');
		if (posfix.not_empty())
			str << posfix;
  	return str;
	}
	return text;
}

void dictionary_translate_menu(MENU_ITEM* menu)
{
  if (menu && dictionary_active()) for (int m = 0; menu[m].tag != 0; m++)
	{
		MENU_ITEM& mi = menu[m];
		if (!mi.separator)
		{
			const char* newtext = dictionary_translate_menu_item(mi.text);
  		if (strlen(newtext) > strlen(mi.text))  // Posso sovrascrivere?
 			  mi.text = xvt_mem_realloc(mi.text, strlen(newtext)+1);
  	  strcpy(mi.text, newtext);
			if (mi.child)
				dictionary_translate_menu(mi.child);
		}
	}
}

bool dictionary_active()
{
  return _DevotoOli != NULL && _DevotoOli->active(); 
}

void dictionary_close()
{
  if (_DevotoOli != NULL)
	{
		delete _DevotoOli;
		_DevotoOli = NULL;
	}
}