/*****************************************************************************
 * $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$
 ****************************************************************************/

#include <iostream>
#include <string>
using namespace std;

#include <pml/PhysicalModel.h>
#include <pml/MultiComponent.h>
#include <pml/StructuralComponent.h>
#include <pml/Atom.h>
#include <math.h>
#include <limits.h>


bool isIn(StructuralComponent* sc, Atom* a) {
    unsigned int i = 0;
    bool found = false;
    while (i < sc->getNumberOfStructures() && !found) {
        found = (sc->getStructure(i) == a);
        i++;
    }
    return found;
}

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

    if (argc != 3 && argc != 4) {
        cout << "Usage:" << endl;
        cout << "\t" << argv[0] << " file.pml \"component\"" << endl;
        cout << "\tRevert inside/out a given component, i.e. turn TRIANGLE and QUAD facet orientation inside/out or outside/in, output to: file-insideout.pml" << endl;
        cout << "PML " << PhysicalModel::VERSION << endl;
        exit(-1);
    }

    try {
        // read the pml
        string filename(argv[1]);
        cout << "-> please wait while reading " << filename << " for reverting orientation of ";
        string c(argv[2]);
        cout << "component " << c << endl;

        PhysicalModel* pm = new PhysicalModel(filename.c_str());

        cout << "-> get " << c << endl;

        // get the component
        Component* cpt = pm->getComponentByName(c);
        if (!cpt) {
            throw PMLAbortException("No component named " + c);
        }
        if (!cpt->isInstanceOf("StructuralComponent")) {
            throw PMLAbortException("Component \"" + c + "\" is not a Structural Component");
        }
        StructuralComponent* sc = (StructuralComponent*) cpt;
        if (sc->composedBy() != StructuralComponent::CELLS || sc->getNumberOfStructures() == 0 || (sc->getCell(0)->getType() != StructureProperties::TRIANGLE &&
                sc->getCell(0)->getType() != StructureProperties::QUAD)) {
            throw PMLAbortException("Component \"" + c + "\": cannot revert component: does not contains any cell geometric type TRIANGLE or QUAD");
        }

        //  Transform "inplace"
        for (unsigned int i = 0; i < cpt->getNumberOfCells(); i++) {
            Cell* c = cpt->getCell(i);
            if (c->getType() == StructureProperties::TRIANGLE
                    || c->getType() == StructureProperties::QUAD) {
                // copy structures
                vector <Structure*> copy;
                for (unsigned int j = 0; j < c->getNumberOfStructures(); j++) {
                    copy.push_back(c->getStructure(j));
                }
                c->deleteAllStructures();
                // invert
                for (int j = copy.size() - 1; j >= 0; j--) {
                    c->addStructure(copy[j]);
                }
            }
        }

        // save the result
        unsigned int pLast = filename.rfind(".");
        if (pLast != string::npos) {
            filename.erase(pLast);
            filename += "-insideout.pml";
        }
        else {
            filename = "insideout.pml";
        }

        cout << "-> please wait while saving " << filename << " " << endl;

        ofstream outputFile(filename.c_str());
        pm->setName(pm->getName() + " reverted " + c);
        // do not optimize output (do not touch cell and atom id)
        pm->xmlPrint(outputFile, false);

        delete pm;

    }
    catch (const PMLAbortException& ae) {
        cout << "AbortException: Physical model aborted:" << endl ;
        cout << ae.what() << endl;
    }
}
