#include <iostream>
#include <qstring.h>
#include <qlist.h>
#include <qtextstream.h>
#include <qfile.h>

using std::cout;
using std::endl;

#include "chemdata.h"
#include "dpoint.h"
#include "text.h"
#include "defs.h"


using std::cout;

bool ChemData::load_mdl(QString fn) {
  QFile f(fn);
  if (!f.open(IO_ReadOnly)) {
    return false;
  }

  // molfiles are formatted text
  QTextStream t(&f);
  QString wholefile = t.read();
  f.close();

  return ProcessMDL(wholefile);
}

bool ChemData::ProcessMDL(QString wf) {
  QTextStream t(&wf, IO_ReadOnly);

  QList<DPoint> atoms;
  QList<Text> labels;
  Text *nt;

  QString tmpline, tfont;
  DPoint *newpt, *s1, *e1;
  int atomcount, bondcount;
  int d1, d2, d3, d4, n, o1;
  double left = 999.0, top = 999.0;
  int bi1 = 0;
  double bd1 = 0.0;
  // first line contains molecule name.  If it starts with $, that probably
  // indicates an MDL file format other than molfile.
  QString line = t.readLine();
  if (line.left(1) == QString("$")) {
    cout << "Can't read this type of MDL file!" << endl;
    return false;
  }
  // Second and third lines contain optional info.  Discard for now
  line = t.readLine();
  line = t.readLine();
  // Fourth line contains counts -- how many atoms, bonds, etc.  Parse values
  line = t.readLine();
  atomcount = line.mid(1, 3).toShort();
  bondcount = line.mid(4, 3).toShort();

  // read in atom lines
  for (n = 0; n < atomcount; n++) {
    line = t.readLine();
    newpt = new DPoint;
    newpt->x = line.mid( 1, 10).toDouble();
    newpt->y = -line.mid(11, 10).toDouble();
    if (newpt->x < left) left = newpt->x;
    if (newpt->y < top) top = newpt->y;
    tmpline = line.mid(31,3);
    tmpline = tmpline.stripWhiteSpace();
    if (tmpline == "COO") tmpline = "COOH";
    if (tmpline != QString("C")) {
      nt = new Text(r);
      nt->setPoint(newpt);
      nt->setJustify(JUSTIFY_CENTER);
      nt->Highlight(true);
      nt->setText(tmpline);
      tmpline.fill(' ');
      nt->setTextMask(tmpline);
      labels.append(nt);
    }
    atoms.append(newpt);
  }
  // now read in bonds - link to atoms read above
  for (n = 0; n < bondcount; n++) {
    line = t.readLine();
    d1 = line.mid(1,3).toShort();
    d2 = line.mid(4,3).toShort();
    d3 = line.mid(7,3).toShort();
    d4 = line.mid(10,3).toShort();
    // remember, QList starts at 0, but atom list in molfile assumed to start
    // at 1, so offset accordingly!
    s1 = atoms.at(d1 - 1);
    e1 = atoms.at(d2 - 1);
    o1 = d3;  // set order
    if (d4 == 1) o1 = 5;  // stereo up
    if (d4 == 6) o1 = 7;  // stereo down
    addBond( s1, e1, 1, o1, QColor(0,0,0), true );
    bd1 += s1->distanceTo(e1);
    bi1++;
  }
  // Add labels after adding bonds
  for (nt = labels.first(); nt != NULL; nt = labels.next() )
    addText(nt);

  double avglen = bd1 / (double)bi1;
  double sf = preferences.getBond_fixedlength() / avglen;

  // scale to match current fixed length
  left *= sf;
  top *= sf;
  for (tmp_pt = atoms.first(); tmp_pt != NULL; tmp_pt = atoms.next() ) {
    tmp_pt->x *= sf;
    tmp_pt->y *= sf;
  }
  // move to fit on page
  cout << left << endl;
  cout << top << endl;
  if ( left < 0.0 )
    Move(-left + 5, 0);
  if ( top < 0.0 )
    Move(0, -top + 5);

  return true;
}

bool ChemData::save_mdl(QString fn) {
  QList<DPoint> up;
  QList<Drawable> uo;
  Text *tmp_text;
  Bond *tmp_bond;
  QString tmpline;
  int acount = 0, bcount = 0;

  // get all unique points and objects
  up = UniquePoints();
  uo = UniqueObjects();

  if (up.count() == 0) return false;  // don't write an empty file

  // open file and text stream
  QFile f(fn);
  if (!f.open(IO_WriteOnly)) {
    return false;
  }  

  QTextStream t(&f);
  
  // Copy text from Text objects to element field in DPoint
  for (tmp_draw = uo.first(); tmp_draw != NULL; tmp_draw = uo.next() ) {
    if (tmp_draw->Type() == TYPE_TEXT) {
      tmp_text = (Text *)tmp_draw;  // is this cheating?
      tmp_text->Start()->element = tmp_text->getText();
    }
  }

  // write first three lines -- blank, unless we want to add comments etc.
  t << endl;
  t << endl;
  t << endl;
  // find counts...
  for (tmp_pt = up.first(); tmp_pt != 0; tmp_pt = up.next() ) {
    acount++;
  }
  for (tmp_draw = uo.first(); tmp_draw != 0; tmp_draw = uo.next() ) {
    if (tmp_draw->Type() == TYPE_BOND) bcount++;
  }
  // write counts line
  t.width(3);
  t << acount;
  t.width(3);
  t << bcount << "  0  0  0  0  0  0  0  0  1" << endl;

  // Write atom list
  for (tmp_pt = up.first(); tmp_pt != NULL; tmp_pt = up.next() ) {
    tmpline = tmp_pt->element;
    if (tmp_pt->element == "HO") tmpline = "OH";
    if (tmpline.length() < 3) tmpline.append(' ');
    if (tmpline.length() < 3) tmpline.append(' ');
    t.width(10);
    t << tmp_pt->x;
    t.width(10);
    t << tmp_pt->y << "    0.0000 " << tmpline;
    t << " 0  0  0  0  0  0  0  0  0  0  0  0" << endl;
  }
  // write bond list
  for (tmp_draw = uo.first(); tmp_draw != NULL; tmp_draw = uo.next() ) {
    if (tmp_draw->Type() == TYPE_BOND) {
      tmp_bond = (Bond *)tmp_draw;  // I ask again, is this cheating?
      t.width(3);
      t << up.find( tmp_bond->Start() ) + 1;
      t.width(3);
      t << up.find( tmp_bond->End() ) + 1;
      t.width(3);
      t << tmp_bond->Order();
      if (tmp_bond->Order() < 4)
	t << "  0  0  0  0" << endl;
      if (tmp_bond->Order() == 5)
	t << "  1  0  0  0" << endl;
      if (tmp_bond->Order() == 7)
	t << "  6  0  0  0" << endl;
    }
  }
  // remember to close file properly
  t << "M  END" << endl;

  f.close();

  return true;
}
