//   Match 2.0.1 -- aligns data series using dynamic programming
//   Copyright (C) 2001-2003  Lorraine E. Lisiecki and Philip A. Lisiecki 
//
//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; version 2
//of the License.
//
//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.
//
//The original authors reserve the right to license this program or
//modified versions of this program under other licenses at our
//discretion.
//
//If you publish results generated by this software please cite
//Lisiecki, L. E. and P. A. Lisiecki, The application of dynamic
//  programming to the correlation of paleoclimate records, 
//  submitted to Paleoceanography, 2001
//
//Any questions regarding this license or the operation of this
//software may be directed to Lorraine Lisiecki
//<zogalum@alum.mit.edu>.

#include "series.hh"

namespace std {}
using namespace std;

string as_string(int i) {
  char buf[sizeof(i)*8];
  sprintf(buf,"%d",i);
  return(buf);
}
string as_string(unsigned int i) {
  char buf[sizeof(i)*8];
  sprintf(buf,"%u",i);
  return(buf);
}
string as_string(float f) {
  char buf[sizeof(f)*8]="";
  snprintf(buf,sizeof(buf)-1,"%f",f);
  return(buf);
}

//Combines multiple single-signal series into a single multi-signal
//series
series merge_signal_series(vector<series> &sv) {
  series s;
  vector<unsigned int> svi(sv.size(),0);
  while(true) {
    bool more=false;
    float depth=0.0;
    int label=0;
    for(unsigned int i=0; i<sv.size(); i++) {
      if(svi[i]<sv[i].cores.size() && 
	 (!more || ((*(sv[i].cores[svi[i]][0]))[0].x<depth))) {
	more=true;
	label=((*(sv[i].cores[svi[i]][0])).label);
	depth=((*(sv[i].cores[svi[i]][0]))[0].x);
      }
    }
    if(!more) break;
    s.cores.push_back(vector<core*>());
    for(unsigned int i=0; i<sv.size(); i++) {
      if(svi[i]<sv[i].cores.size() && 
	 (sv[i].cores[svi[i]][0]->label==label)) {
	s.cores.back().push_back(sv[i].cores[svi[i]][0]);
	svi[i]++;
      } else {
	s.cores.back().push_back(new core(label));
      }
    }
  }
  return s;
}

series readfile(string name) {
  ifstream in(name.c_str());
  assert(in);

  series s;
  s.cores.push_back(vector<core*>());
  s.cores.back().push_back(new core);
  int lastinputcorenum=-1;
  string line;

  while(!in.eof() && !in.fail() && getline(in,line)) {
    int n;
    float a,b,c;

    n=sscanf(line.c_str(), "%f %f %f", &a,&b,&c);
    if(n>=2) {
      point p;
      if(n==2) {
	p.x=a;
	p.y=b;
      }
      else {
	if(a!=lastinputcorenum && lastinputcorenum!=-1) {
	  s.cores.push_back(vector<core*>());
	  s.cores.back().push_back(new core);
	}
	lastinputcorenum=int(a);
	s.cores.back().back()->label=lastinputcorenum;
	p.x=b;
	p.y=c;
      }
      s.cores.back().back()->add(p);
    }
  }
  return s;
}

bool writefile(ostream &out,series &s, int signalnum) {
  //  out << "# SGR" << endl;
  for(unsigned i=0; i<s.cores.size(); i++) {
    core &c=*(s.cores[i][signalnum]);
    for(int j=0; j<c.size; j++)
      out << c[j].x << " " << c[j].y << endl;
  }
  return out;
}

bool writefile(string name,series &s, int signalnum) {
  ofstream out(name.c_str());
  return writefile(out,s, signalnum);
}

tiepts read_tiefile(string name, ostream &log) throw(format_error) {
  ifstream in(name.c_str());
  if(!in)
    throw format_error("Error opening tie file");

  tiepts t;
  int columns=-1;
  string line;
  log<<"Tiepoints:"<<endl;

  while(!in.eof() && !in.fail() && getline(in,line)) {
    int n;
    float a,b,c,d,e;

    n=sscanf(line.c_str(), "%f %f %f %f %f", &a,&b,&c,&d,&e);
    if(n==1) {
      throw format_error("Tie point file has only one column");
    } else if(n>=2) {
      if(columns == -1) columns=n;
      if(columns != n) 
	throw format_error("Tie point file has inconsistent columns");
      switch (n) {
      case 2:
	t.raw.push_back(tiept(0,a,0,b,1.0));
	log<<int(a)<<" "<<b<<endl;
	break;
      case 3:
	t.raw.push_back(tiept(0,a,0,b,c));
	log<<int(a)<<" "<<b<<" "<<c<<endl;
	break;
      case 4:
	t.raw.push_back(tiept(int(a),b,int(c),d,1.0));
	log<<int(a)<<" "<<b<<" "<<int(c)<<" "<<d<<endl;
	break;
      case 5:
	t.raw.push_back(tiept(int(a),b,int(c),d,e));
	log<<int(a)<<" "<<b<<" "<<int(c)<<" "<<d<<" "<<e<<endl;
	break;
      default:
	throw format_error("Tie point file-- internal error");
      }
    }
  }
  if(!in.eof())
    throw format_error("Error reading tie file");
  return t;
}

gaps read_gapfile(string name) throw(format_error) {
  ifstream in(name.c_str());
  if(!in)
    throw format_error("Error opening gap file");

  gaps g;
  string line;

  while(!in.eof() && !in.fail() && getline(in,line)) {
    int n, i, j, a;
    float b=0.0,c=0.0;
    char dummy;
    bool bnan=false, cnan=false;

    n=sscanf(line.c_str(), "%d%n", &a,&i);
    if(n>=1) {
      n=sscanf(line.c_str()+i, " %f%n", &b, &j);
      if(n==0) {
	n=sscanf(line.c_str()+i, " %*1[Nn]%*1[Aa]%1[Nn]%n", &dummy, &j);
	if(n!=1)
	  throw format_error("Invalid gap file format");
	b=0.0;
	bnan=true;
      }
      i+=j;
      n=sscanf(line.c_str()+i, " %f%n", &c, &j);
      if(n==0) {
	n=sscanf(line.c_str()+i, " %*1[Nn]%*1[Aa]%1[Nn]%n", &dummy, &j);
	if(n!=1)
	  throw format_error("Invalid gap file format");
	c=0.0;
	cnan=true;
      }
      //      cerr<<"gap: "<<a<<" "<<b<<" "<<bnan<<" "<<c<<" "<<cnan<<endl;
      if(!bnan && !cnan && b>c)
	throw format_error("gap start > gap end");
      g.raw.push_back(gap(a,b,bnan,c,cnan));
    }
  }
  if(!in.eof())
    throw format_error("Error reading gap file");
  return g;
}
