/**********************************************************************
 *
 * cfgread.cpp -- 
 * Copyright (C) 1999  The New Zealand Digital Library Project
 *
 * A component of the Greenstone digital library software
 * from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *********************************************************************/

#include "cfgread.h"
#include <cctype> // for isspace()

int write_ini_line (ofstream &fileout, const text_t &key, const text_t &value) {
  if (key.empty() || value.empty()) return -1;
  outconvertclass text_t2ascii;
  fileout << text_t2ascii << key << "=" << value << "\n";
  return 0;
}

int read_ini_line (ifstream &filein, text_t &key, text_t &value) {
  if (filein.eof()) return -1;

  key.clear();
  value.clear();
  char c;
  filein.get(c);

  int foundeq = 0;
  while (!filein.eof() && c != '\n') {
    if (!foundeq && c == '=') {
		foundeq = 1;
		filein.get(c);
		// now that we've read the next character, we should check it's not \n
		// if it is, then we had a line of the form 'hostIP=', and we should exit the loop
		if (c == '\n') break;		
	}
    if (foundeq) value.push_back(c);
    else key.push_back(c);
    filein.get(c);
  }
  if (key.empty()) return 0; // blank line maybe?
  return 0;
} 

// write out line of values to cfgfile
// does nothing fancy - make sure no values contain carriage returns
int write_cfg_line (ofstream &fileout, const text_tarray &values) {
  outconvertclass text_t2ascii;

  text_tarray::const_iterator here = values.begin();
  text_tarray::const_iterator end = values.end();

  bool first = true;
  while (here != end) {
    if (first) fileout << text_t2ascii << *here;
    else fileout << text_t2ascii << "  \"" << *here << "\"";
    first = false;
    ++here;
  }
  fileout << "\n";
  return 0;
}

// same, but use a file descriptor this time
int write_cfg_line (int fileout, const text_tarray &values) {
  outconvertclass text_t2ascii;

  text_tarray::const_iterator here = values.begin();
  text_tarray::const_iterator end = values.end();

  if (here != end) {
    char *s=here->getcstr();
    write(fileout,s ,here->size());
    delete []s;

    ++here;
  }
  while (here != end) {
    write(fileout, " \"", 2);
    char *s=here->getcstr();
    write(fileout,s ,here->size());
    delete []s;
    write(fileout, "\"", 1);

    ++here;
  }
  write(fileout,"\n",1);
  return 0;
}


// returns 0 on success, -1 on failure
int read_cfg_line (ifstream &filein, text_tarray &values) {
  // we split up the line into tokens, pushing each token into the
  // values array. Quoted phrases are a single token. A "\" at the end
  // of a line continues onto the next line.

  values.erase(values.begin(), values.end());

  if (!filein.good()) return -1;

  text_t curvalue;
  char c1;
  filein.get(c1);

  // skip white space
  while (!filein.eof() && isspace((unsigned char) c1)) { filein.get(c1); }

    // ignore comments
  while (!filein.eof() && c1 == '#') {
    while (!filein.eof() && c1!='\n' && c1!='\r') { filein.get(c1); }
    // skip white space...
    while (!filein.eof() && isspace((unsigned char) c1)) { filein.get(c1); }
  }

  // deal with all the records on this line (possibly multi-line)

  while (!filein.eof()) {
    if (c1=='\n' || c1=='\r') { // shouldn't happen?
      break;
    }

    // get the next token
    curvalue.clear();
      
    bool inquote=false;
    char quotemark='"';
    char preceding='\0'; // 1-char state to allow \" and \'
    // see if this is a quoted phrase
    if (c1=='\'' || c1=='\"') { // starts with a quote
      inquote=true;
      quotemark = c1;
      preceding = c1; // just to initialise
      filein.get(c1);
    }

    // get token or a whole phrase
    while (!filein.eof()) {
      if (isspace((unsigned char) c1)) {
	if (! inquote) {
	  // end of token, not inside quote marks
	  break;
	} else {
	  // inside quote marks.
	  /* Turn eol into space, in case other parsing bits expect eol to
	     also mean end of parsing... */
	  c1=' ';
	}
      }
      if (c1 == quotemark && inquote && preceding != '\\') {
	// end of quoted phrase found
	inquote=false;
	filein.get(c1);
	continue;
      }

      // add current char to token/phrase
      // see if current byte is part of a multibyte char (utf-8 only!)
      unsigned short int c; // text_t uses 16bit unicode
      unsigned char uc1=(unsigned)c1;
      if (uc1 < 0x80) {
	c=uc1;
      } else if (uc1 >= 0xc0 && uc1 <= 0xdf) {
	// 2-byte utf-8
	unsigned char c2;
	// two byte character
	filein.get((char&)c2); // get takes a signed char
	c = ((uc1 & 0x1f) << 6) + (c2 & 0x3f);
      } else if (uc1 >= 0xe0 && uc1 <= 0xef) {
	// 3-byte character
	unsigned char c2, c3;
	filein.get((char&)c2);
	filein.get((char&)c3);
	c = ((uc1 & 0xf) << 12) + ((c2 & 0x3f) << 6)
	  + (c3 & 0x3f);
      } else {c=uc1;} // we don't do group2/plane0 (4,5,6-byte utf-8)

      curvalue.push_back(c); // 16bit unicode
      if (inquote)
	preceding = c1;

      filein.get(c1);
    }
    // we now have a token or a phrase
    
    // see if we've reached the end of the line
    if (c1 == '\n' || c1 == '\r') {
      if (curvalue != "\\") { // the line DOESN'T continue. End of line.
	values.push_back(curvalue);
	break; // end of token/phrase
      } else {
	// swallow up the EOL chars
	while (!filein.eof() && (c1=='\r' || c1=='\n')) filein.get(c1);
	// the current token "\\" will be cleared below
      }
    } else { // no new line seen
      values.push_back(curvalue);
    }

    curvalue.clear();

    // remove whitespace (but not newline/CR chars) before next token
    while (!filein.eof() && (c1==' ' || c1=='\t')) filein.get(c1);

  } // while(1)
  

  return 0;
}
