/*************************************************************************
 *    CompuCell - A software framework for multimodel simulations of     *
 * biocomplexity problems Copyright (C) 2003 University of Notre Dame,   *
 *                             Indiana                                   *
 *                                                                       *
 * This program is free software; IF YOU AGREE TO CITE USE OF CompuCell  *
 *  IN ALL RELATED RESEARCH PUBLICATIONS according to the terms of the   *
 *  CompuCell GNU General Public License RIDER 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 "TripleVizDumper.h"

#include <CompuCell3D/Simulator.h>
#include <CompuCell3D/ClassRegistry.h>
#include <CompuCell3D/Viz/FieldRenderer.h>
#include <CompuCell3D/Field3D/Field3D.h>
#include <CompuCell3D/Potts3D/Potts3D.h>
#include <CompuCell3D/Potts3D/Cell.h>
using namespace CompuCell3D;

#include <XMLCereal/XMLPullParser.h>
#include <XMLCereal/XMLSerializer.h>

#include <BasicUtils/BasicString.h>

using namespace std;

#include <stdio.h>

#include <config.h>
#ifdef HAVE_ZLIB
#include <zlib.h>
#define ZOPEN  gzopen
#define ZPUTC  gzputc
#define ZPUTS  gzputs
#define ZFILE  gzFile
#define ZCLOSE gzclose
#define SUFFIX ".dat.gz"
#else
#define ZOPEN  fopen
#define ZPUTC(file, c)  putc(c, file)
#define ZPUTS(file, s)  puts(s, file)
#define ZPUTC(file,c)  fputc(c,file)
#define ZPUTS(file,s)  fputs(s,file)
#define ZFILE  FILE *
#define ZCLOSE fclose
#define SUFFIX ".dat"
#endif

void TripleVizDumper::step(const unsigned int currentStep) {
  ASSERT_OR_THROW("dumpVizField() No renderer set!", renderer);

  Dim3D dim = renderer->getDim();
  Dim3D dim2 = gridSize;
  
  if (dim.z > dim2.z)
      dim2 = dim;

  char buf[512];
  sprintf(buf, "%ix%ix%i-%i-%c%c%c%c", dim.x, dim.y, dim.z, 1,
	  'c', 'u', 'o', 'n');

  string prefix =  BasicString(currentStep);
  if (filePrefix != "") prefix = filePrefix + "-" + prefix;
  string redFilename = prefix + "-red-" + buf + SUFFIX;
  string greenFilename = prefix + "-grn-" + buf + SUFFIX;
  string blueFilename = prefix + "-blu-" + buf + SUFFIX;
  string opacityFilename = prefix + "-opc-" + buf + SUFFIX;

  string redFilenameC = prefix + "-red-" + buf + "-target-" + SUFFIX;
  string greenFilenameC = prefix + "-grn-" + buf + "-target-" + SUFFIX;
  string blueFilenameC = prefix + "-blu-" + buf + "-target-" + SUFFIX;
  string opacityFilenameC = prefix + "-opc-" + buf + "-target-" + SUFFIX;

  string redFilenameN = prefix + "-red-" + buf + "-nontarget-" + SUFFIX;
  string greenFilenameN = prefix + "-grn-" + buf + "-nontarget-" + SUFFIX;
  string blueFilenameN = prefix + "-blu-" + buf + "-nontarget-" + SUFFIX;
  string opacityFilenameN = prefix + "-opc-" + buf + "-nontarget-" + SUFFIX;
  
  ZFILE redFile = ZOPEN(redFilename.c_str(), "w");
  ZFILE greenFile = ZOPEN(greenFilename.c_str(), "w");
  ZFILE blueFile = ZOPEN(blueFilename.c_str(), "w");
  ZFILE opacityFile = ZOPEN(opacityFilename.c_str(), "w");

  
  ZFILE redFileC = ZOPEN(redFilenameC.c_str(), "w");
  ZFILE greenFileC = ZOPEN(greenFilenameC.c_str(), "w");
  ZFILE blueFileC = ZOPEN(blueFilenameC.c_str(), "w");
  ZFILE opacityFileC = ZOPEN(opacityFilenameC.c_str(), "w");
  
  ZFILE redFileN = ZOPEN(redFilenameN.c_str(), "w");
  ZFILE greenFileN = ZOPEN(greenFilenameN.c_str(), "w");
  ZFILE blueFileN = ZOPEN(blueFilenameN.c_str(), "w");
  ZFILE opacityFileN = ZOPEN(opacityFilenameN.c_str(), "w");
  
  Point3D pt;
  VizProperties props;
  for (pt.z = 0; pt.z < dim2.z; pt.z++)
    for (pt.y = 0; pt.y < dim2.y; pt.y++)
      for (pt.x = 0; pt.x < dim2.x; pt.x++) {
	
        if ((pt.x < dim.x) && (pt.y < dim.y) && (pt.z < dim.z))
        {
           props = renderer->get(pt);
	
           ZPUTC(redFile, (unsigned char)props.red);
	   ZPUTC(greenFile, (unsigned char)props.green);
	   ZPUTC(blueFile, (unsigned char)props.blue);
	   ZPUTC(opacityFile, (unsigned char)props.opacity);
        
           if ((props.red == tred) &&
               (props.green == tgreen) &&
               (props.blue == tblue) &&
               (props.opacity == topacity)) // Target
           {
               ZPUTC(redFileC, (unsigned char)props.red);
               ZPUTC(greenFileC, (unsigned char)props.green);
               ZPUTC(blueFileC, (unsigned char)props.blue);
               ZPUTC(opacityFileC, (unsigned char)props.opacity);
               ZPUTC(redFileN, (unsigned char)0);
               ZPUTC(greenFileN, (unsigned char)0);
               ZPUTC(blueFileN, (unsigned char)0);
               ZPUTC(opacityFileN, (unsigned char)0);
           }
           else
           {
               ZPUTC(redFileN, (unsigned char)props.red);
               ZPUTC(greenFileN, (unsigned char)props.green);
               ZPUTC(blueFileN, (unsigned char)props.blue);
               ZPUTC(opacityFileN, (unsigned char)props.opacity);
               ZPUTC(redFileC, (unsigned char)0);
               ZPUTC(greenFileC, (unsigned char)0);
               ZPUTC(blueFileC, (unsigned char)0);
               ZPUTC(opacityFileC, (unsigned char)0);
           }    
        }
        else // Growth
        {
           ZPUTC(redFile, (unsigned char)0);
           ZPUTC(greenFile, (unsigned char)0);
           ZPUTC(blueFile, (unsigned char)0);
           ZPUTC(opacityFile, (unsigned char)0);
           ZPUTC(redFileC, (unsigned char)0);
           ZPUTC(greenFileC, (unsigned char)0);
           ZPUTC(blueFileC, (unsigned char)0);
           ZPUTC(opacityFileC, (unsigned char)0);
           ZPUTC(redFileN, (unsigned char)0);
           ZPUTC(greenFileN, (unsigned char)0);
           ZPUTC(blueFileN, (unsigned char)0);
           ZPUTC(opacityFileN, (unsigned char)0);
        }
      }

  ZPUTS(redFile, "MIN 0 MAX 255\n");
  ZPUTS(greenFile, "MIN 0 MAX 255\n");
  ZPUTS(blueFile, "MIN 0 MAX 255\n");
  ZPUTS(opacityFile, "MIN 0 MAX 255\n");
  

  ZPUTS(redFileC, "MIN 0 MAX 255\n");
  ZPUTS(greenFileC, "MIN 0 MAX 255\n");
  ZPUTS(blueFileC, "MIN 0 MAX 255\n");
  ZPUTS(opacityFileC, "MIN 0 MAX 255\n");
  
  
  ZPUTS(redFileN, "MIN 0 MAX 255\n");
  ZPUTS(greenFileN, "MIN 0 MAX 255\n");
  ZPUTS(blueFileN, "MIN 0 MAX 255\n");
  ZPUTS(opacityFileN, "MIN 0 MAX 255\n");
  
  ZCLOSE(redFile);
  ZCLOSE(greenFile);
  ZCLOSE(blueFile);
  ZCLOSE(opacityFile);


  ZCLOSE(redFileC);
  ZCLOSE(greenFileC);
  ZCLOSE(blueFileC);
  ZCLOSE(opacityFileC);

  ZCLOSE(redFileN);
  ZCLOSE(greenFileN);
  ZCLOSE(blueFileN);
  ZCLOSE(opacityFileN);
}



void TripleVizDumper::readXML(XMLPullParser &in) {
  in.skip(TEXT);

  while (in.check(START_ELEMENT)) {
    if (in.getName() == "FilePrefix") {
      filePrefix = BasicString::trim(in.matchSimple());

    } 
    else if (in.getName() == "Target") {
      tred = BasicString::parseUInteger(in.getAttribute("red").value);
      tgreen = BasicString::parseUInteger(in.getAttribute("green").value);
      tblue = BasicString::parseUInteger(in.getAttribute("blue").value);
      topacity = BasicString::parseUInteger(in.getAttribute("opacity").value);
      in.matchSimple();
    }
    
    else if (in.getName() == "Dimensions") {
      Dim3D dim;
      dim.readXML(in);
      in.matchSimple();
      gridSize = dim;
      //potts.createCellField(dim);
    }
    
    else if (in.getName() == "Renderer") {
      ClassRegistry *reg = simulator->getClassRegistry();
      renderer = reg->getRenderer(BasicString::trim(in.matchSimple()));

    } else {
      throw BasicException(string("Unexpected element '") + in.getName() + 
			   "'!", in.getLocation());
    }

    in.skip(TEXT);
  }

  ASSERT_OR_THROW("You must set a Renderer!", renderer);
}

void TripleVizDumper::writeXML(XMLSerializer &out) {
}
