/** 
 *  Yudit Unicode Editor Source File
 *
 *  GNU Copyright (C) 1997-2006  Gaspar Sinai <gaspar@yudit.org>  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, version 2,
 *  dated June 1991. See file COPYYING for details.
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
#include <stoolkit/SUniMap.h>
#include <stoolkit/SEncoder.h>
#include <stoolkit/SExcept.h>
#include <stoolkit/SString.h>
#include <stoolkit/STypes.h>
#include <stoolkit/SUtil.h>
#include <stoolkit/SStringVector.h>
#include <stoolkit/SIO.h>


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

#define BUFFER_SIZE 512

static const char *version="uniconv version %s GNU(c) Gaspar Sinai\n";
static void usage ();

#define SS_UNIX 0
#define SS_DOS 1
#define SS_MAC 2
/**
 * This is a stoolkit encoder/decoder
 * @author: Gaspar Sinai <gaspar@yudit.org>
 * @version: 2000-04-23
 * This library is not multi-threaded. Therefor we need event handlers.
 */
int
main (int argc, char *argv[])
{
  const char* ifile="-";
  const char* ofile="-";
  FILE* output=stdout;
  FILE* input=stdin;
  const char* iencoding="utf-8";
  const char* oencoding="utf-8";
  int   fromd = SS_UNIX;
  int   tod = SS_UNIX;

  SUniMap::guessPath();
 
  int i;
  for (i=1; i<argc; i++)
  {
    if (strcmp ("-encode", argv[i])==0 && i<argc-1)
    { 
      oencoding =  argv[i+1]; i++;
    }
    else if (strcmp ("-fromdos", argv[i])==0)
    { 
      fromd = SS_DOS;
    }
    else if (strcmp ("-todos", argv[i])==0)
    { 
      tod = SS_DOS;
    }
    else if (strcmp ("-tomac", argv[i])==0)
    { 
      tod = SS_MAC;
    }
    else if (strcmp ("-frommac", argv[i])==0)
    { 
      fromd = SS_MAC;
    }
    else if (strcmp ("-decode", argv[i])==0 && i<argc-1)
    { 
      iencoding =  argv[i+1]; i++;
    }
    else if (strcmp ("-out", argv[i])==0 && i<argc-1)
    { 
      ofile =  argv[i+1]; i++;
#ifdef USE_WINAPI
      if ((output = fopen (ofile, "wb")) == 0)
#else
      if ((output = fopen (ofile, "w")) == 0)
#endif
      {
        fprintf (stderr, "uniconv: can not open '%s' to write.\n", ofile);
        return 1;
      }
    }
    else if (strcmp ("-in", argv[i])==0 && i<argc-1)
    { 
      ifile =  argv[i+1]; i++;
#ifdef USE_WINAPI
      if ((input = fopen (ifile, "rb")) == 0)
#else
      if ((input = fopen (ifile, "r")) == 0)
#endif
      {
        fprintf (stderr, "uniconv: can not open '%s' to read.\n", ifile);
        return 1;
      }
    }
    else
    {
      usage();
      return 1;
    }
  }
  SEncoder ic(iencoding);
  if (!ic.isOK())
  {
    fprintf (stderr, "uniconv: can not find converter '%s'\n", iencoding);
    return 1;
  }
  SEncoder oc(oencoding);
  if (!oc.isOK())
  {
    fprintf (stderr, "uniconv: can not find converter '%s'\n", oencoding);
    return 1;
  }
  SStringVector lines;
  SString remaining;
  SStringVector delimiters = ic.delimiters();
  char* buff = new char[BUFFER_SIZE];
  CHECK_NEW (buff);
  int len; 
  SV_UCS4 dosrn;
  dosrn.append((SS_UCS4) '\r');
  dosrn.append((SS_UCS4) '\n');
  SV_UCS4 unixn;
  unixn.append((SS_UCS4) '\n');
  SV_UCS4 macr;
  macr.append((SS_UCS4) '\r');
  int crpending = 0;
  while (!feof(input) && (len=fread(buff, 1, BUFFER_SIZE, input))>0)
  {
    if (buff[len-1] == '\r')
    {
      crpending = 1;
      len--;
      if (!len) break;
    }
    SString s(buff, len);
    remaining.append(s);
    /* this will not work if last line does not have a proper ending */
    while (true)
    {
      int found =-1;
      unsigned int i;
      for (i=0; i<delimiters.size(); i++)
      {
         found = remaining.find (delimiters[i]);
         if (found>=0) break;
      }
      if (found < 0) break;
      unsigned int ind = found+delimiters[i].size();
      SString a(remaining.array(), ind);
      lines.append (a);
      remaining.remove (0, ind);
    }
    for (unsigned k=0; k<lines.size(); k++)
    {
      SV_UCS4 res = ic.decode (lines[k]);
      if (fromd == SS_DOS)
      {
        res.replaceAll(dosrn, unixn);
      }
      if (fromd == SS_MAC)
      {
        res.replaceAll(macr, unixn);
      }
      if (tod == SS_MAC)
      {
        res.replaceAll(unixn, macr);
      }
      if (tod == SS_DOS)
      {
        res.replaceAll(dosrn, unixn);
        res.replaceAll(unixn, dosrn);
      }
      if (res.size() != 0)
      {
        SString w = oc.encode (res);
        int wlen = fwrite(w.array(), 1, w.size(), output);
        if (wlen!= (int) w.size())
        {
          fprintf (stderr, "uniconv: failed to write %s.\n", ofile);
          delete[] buff;
          return 1;
        }
      }
    }
    lines.clear();
    if (crpending)
    {
      remaining.append("\r");
      crpending = 0;
    }
  }
  if (crpending)
  {
    remaining.append("\r");
  }
  if (remaining.size() != 0)
  {
    SV_UCS4 res = ic.decode (remaining, false);
    if (fromd == SS_DOS)
    {
      res.replaceAll (dosrn, unixn);
    }
    if (fromd == SS_MAC)
    {
      res.replaceAll(macr, unixn);
    }
    if (tod == SS_MAC)
    {
      res.replaceAll(unixn, macr);
    }
    if (tod == SS_DOS)
    {
      res.replaceAll (dosrn, unixn);
      res.replaceAll (unixn, dosrn);
    }
    SString w = oc.encode (res);
    int wlen = fwrite(w.array(), 1, w.size(), output);
    if (wlen!= (int) w.size())
    {
      fprintf (stderr, "uniconv: failed to write %s [%d/%d].\n", ofile, wlen, w.size());
      delete[] buff;
      return 1;
    }
  }
  fclose (input);
  fclose (output);
  delete[] buff;
  return 0;
}

static void
usage ()
{
  SString pathStr;
  SStringVector l = SUniMap::getPath();
  
#ifdef USE_WINAPI
  pathStr = l.join (";");
#else
  pathStr = l.join (":");
#endif

  SStringVector enc = SEncoder::builtin();
  SString supStr = enc.join(", ");

  SStringVector extEnc = SEncoder::external();
  SString supExt = extEnc.join(", ");


  fprintf (stdout, version, SD_YUDIT_VERSION);
  fprintf (stdout,   "USAGE: uniconv [-out file] [-in file] [-decode name] [-encode name] [-fromdos] [-todos] [-frommac] [-tomac] \n\n");
  fprintf (stdout, "Currently known built-in encodings:   \n");
  fprintf (stdout, "%*.*s\n\n", SSARGS(supStr));
  fprintf (stdout, "Currently known external encodings:   \n");
  fprintf (stdout, "%*.*s\n\n", SSARGS(supExt));
  fprintf (stdout, "datapath settings:\n %*.*s.\n\n", SSARGS(pathStr));
  fprintf (stdout, "example: /uniconv -decode Hungarian -encode iso-8859-2\n");
  fprintf (stdout, "example: Sinai Ga'spa'r <eof>\n");
}

