/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK 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 Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/
//
// C++ Implementation: vtk2pml
//
// Description: very simple vtk unstructured grid export to pml
// Note: this transformation is done manually, without the help of the VTK API
// Pros: no dependencies
// Cons: lots of things/case/vtk types not take into account, very simple transformation
//
// the first argument is the name of a vtk file

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <sstream>

using namespace std;

// the input .obj file
std::ifstream vtkFile;
unsigned lineNr;
bool eof;

typedef struct {
    string directive;
    string data;
    bool ok;
} ObjLine;

ObjLine currentLine;

// -------------------- getNext ------------------------
// get the next current line
void getNext() {
    char l[200];
    string line;
    currentLine.ok = false;

    while (!eof && !currentLine.ok) {
        eof = !(vtkFile.getline(l, 199));
        lineNr++;

        if (l[0] != '#') {
            line = l;

            unsigned int space = line.find(' ');

            if (space != string::npos && space != 0) {
                currentLine.directive = line.substr(0, space);
                currentLine.data = line.substr(space + 1);
                currentLine.ok = true;
            }
        }
    }

}


// -------------------- getCountFromDirective ------------------------
int getCountFromDirective(string directive) {
    // go to the first directive
    while (!eof && currentLine.directive != directive) {
//  cout << "l=" << currentLine.directive << endl;
        getNext();
    }

    if (!eof) {
        return atoi(currentLine.data.c_str());
    }
    else {
        return 0;
    }
}


// -------------------- getVector ------------------------
// get the double 3D vector in the current data
void getVector(double d[3]) {
    stringstream data(currentLine.data, std::stringstream::in);

    for (unsigned int i = 0; i < 3; i++) {
        data >> d[i];
    }
}

int main(int argc, char** argv) {

    if (argc != 2) {
        cout << "usage: " << argv[0] << endl;
        cout << "\t" << argv[0] << " file.vtk" << endl;
        exit(-1);
    }

    // get the vtk filename
    string filename(argv[1]);

    // create output file name
    string outFilename = filename;

    unsigned int pLast = outFilename.rfind(".");

    if (pLast != string::npos) {
        outFilename.erase(pLast);
        outFilename += ".pml";
    }
    else {
        outFilename += "-pml";
    }

    // read the vtk file
    vtkFile.open(filename.c_str());

    if (!vtkFile) {
        cerr << "Error: Can't open the file named " << filename << endl;
        exit(1);
    }

    ofstream outputFile(outFilename.c_str());

    cout << "Transforming vtk to pml..." << endl;
    outputFile << "<!-- Created by vtk2pml (c) E Promayon, TIMC (c) 2009 -->" << endl;

    outputFile << "<physicalModel name=\"from vtk\" >" << endl;

    // atoms
    // looking for "POINTS n float"
    unsigned int nAtoms = getCountFromDirective("POINTS");
    //cout << "Found " << nAtoms << " atoms." << endl;

    outputFile << "<atoms>" << endl;

    outputFile << "<structuralComponent name=\"vertices\">" << endl;

    double x, y, z;

    for (unsigned int i = 1; i <= nAtoms; i++) {
        // read position
        vtkFile >> x;
        vtkFile >> y;
        vtkFile >> z;
        // write atom
        outputFile << "<atom>" << endl;
        // indexes start at 0
        outputFile << "<atomProperties index=\"" << i - 1 << "\" x=\"" << x << "\"  y=\"" << y << "\" z=\"" << z << "\"  />" << endl;
        outputFile << "</atom>" << endl;
    }

    outputFile << "</structuralComponent>" << endl;

    outputFile << "</atoms>" << endl;

    cout <<  "-> created " << nAtoms << " atoms" << endl;

    // regions
    outputFile << "<exclusiveComponents>" << endl;
    outputFile << "<multiComponent name=\"Exclusive Components\">" << endl;
    outputFile << "<structuralComponent name=\"Regions\" mass=\"1\" viscosityW=\"1\" >" << endl;
    outputFile << "<cell>" << endl;
    outputFile << "<cellProperties name=\"cell\" mode=\"NONE\" type=\"POLY_VERTEX\" materialType=\"elastic\" shapeW=\"300\" masterRegion=\"1\" incompressibility=\"0\" />" << endl;
    outputFile << "<color r=\"0.8\" g=\"0.8\" b=\"0.2\" a=\"1.0\" />" << endl;

    for (unsigned int i = 1; i <= nAtoms; i++) {
        outputFile << "<atomRef index=\"" << i - 1 <<  "\"/>" << endl;
    }

    outputFile << "</cell>" << endl;

    outputFile << "</structuralComponent>" << endl;

    cout <<  "-> created region" << endl;

// tetrahedra => elements (we can then convert the elements to neighborhood using the corresponding physicalmodel lib tool)
    unsigned int nPolygons = getCountFromDirective("POLYGONS");

    outputFile << "<structuralComponent name=\"Elements\"  mode=\"WIREFRAME_AND_SURFACE\" >" << endl;

    outputFile << "<color r=\".95\" g=\"0.89\" b=\"0.63\" a=\"1.0\"/>" << endl;

    cout <<  "-> creating polygons (nb of polygons to read=" << nPolygons << ")" << endl;

    int id;
    int nPoints;

    for (unsigned int i = 0; i < nPolygons; i++) {
        outputFile << "<cell>" << endl;
        outputFile << "<cellProperties type=\"";
        vtkFile >> nPoints;

        switch (nPoints) {
            case 3:
            default:
                outputFile << "TRIANGLE\" />" << endl;
                break;
        }

        for (unsigned int j = 0; j < nPoints; j++) {
            vtkFile >> id;
            outputFile << "<atomRef index=\"" << id << "\" />" << endl;
        }

        /*    // discard the next "offset" number of integer
            for ( unsigned int j=0; j<offset; j++ )
              vtkFile >> id;
        */
        outputFile << "</cell>" << endl;
    }

    cout <<  "...finished (" << nPolygons << " polygons created)" << endl;

    cout << "Results in " << outFilename << endl;

    outputFile << "</structuralComponent>" << endl;
    outputFile << "</multiComponent>" << endl;
    outputFile << "</exclusiveComponents>" << endl;
    outputFile << "</physicalModel>" << endl;

    outputFile.close();

}
