/* main.cpp */

/**
 * Author   :   Yuri Meiburg
 * 2011
 * Rijksuniversiteit Groningen
 * MSC. Computational Science and Visualization

 * imConvert 
 *
 * This program can read PGM files, and convert them to the SIR method,
 * which stands for "Skeletonal Image Representation". It is in a very
 * early research state, so no GUI, no broad image support, and not
 * heavily optimized for speed.
 *
 * To view SIR-files, use imShow.
 * 
 * This program is supplementary to my thesis.
 */



#include <math.h>
#include <string>

#include "main.hpp"
#include "include/Image.hpp"
#include "include/io.hpp"
#include "include/messages.h"
#include "configParser/include/Config.hpp"
#include "include/ImageStatistics.hpp"

using namespace std;


/* All properties that can be set in the config files: */
/* For a more detailed explanation, see our example.conf */
int MSG_LEVEL = MSG_NORMAL;
const char *filename = 0;

/* Image space variables */
int islandThreshold = 0;
float layerThreshold = 0;
extern float SKELETON_DT_THRESHOLD;
extern unsigned int SKELETON_SALIENCY_THRESHOLD;
extern unsigned int SKELETON_ISLAND_THRESHOLD;
extern string OUTPUT_FILE;

/* Tree variables */
extern int MIN_OBJECT_SIZE;
extern int MIN_SUM_RADIUS;
extern int MIN_PATH_LENGTH;

/* Set all parameters according to the configuration file parsed
 * with the Config object */
void setConfig(Config c) {

    if (!c.exists("filename")) {
        cout << "Please specify a filename" << endl;
        exit(-1);
    }
    filename = c.pString("filename").c_str();

    if (!c.exists("outputLevel")) {
        MSG_LEVEL = MSG_NORMAL;
    } else {
        switch (c.pString("outputLevel")[0]) {
            case 'q':
                MSG_LEVEL = MSG_NEVER;
                break;
            case 'e':
                MSG_LEVEL = MSG_ERROR;
                break;
            case 'n':
                MSG_LEVEL = MSG_NORMAL;
                break;
            case 'v':
                MSG_LEVEL = MSG_VERBOSE;
                break;
        }
    }

    layerThreshold = c.exists("lThreshold") ? c.pDouble("lThreshold") : 0;
    islandThreshold = c.exists("sThreshold") ? c.pInt("sThreshold") : 0;
    SKELETON_DT_THRESHOLD = c.exists("sdtThreshold") ? c.pDouble("sdtThreshold") : 5;
    SKELETON_SALIENCY_THRESHOLD = c.exists("ssThreshold") ? c.pInt("ssThreshold") : 5;
    SKELETON_ISLAND_THRESHOLD = c.exists("siThreshold") ? c.pInt("siThreshold") : 10;

    MIN_OBJECT_SIZE = c.exists("minObjSize") ? c.pInt("minObjSize") : 5;
    MIN_SUM_RADIUS = c.exists("minSumRadius") ? c.pInt("minSumRadius") : 15;
    MIN_PATH_LENGTH = c.exists("minPathLength") ? c.pInt("minPathLength") : 3;

    OUTPUT_FILE = c.exists("outputFile") ? c.pString("outputFile") : "default.sir";

    /* output all settings, so we can check if it parsed correctly. */
    PRINT(MSG_NORMAL, "\n\n-------- Begin Configuration --------\n\n");
    PRINT(MSG_NORMAL, "Output level: %s\n", MSG_LEVEL == MSG_NORMAL ? "Normal" : MSG_LEVEL == MSG_VERBOSE ? "Verbose" : "None");
    PRINT(MSG_NORMAL, "File in: %s\n", filename);
    PRINT(MSG_NORMAL, "File out: %s\n", OUTPUT_FILE.c_str());
    PRINT(MSG_NORMAL, "Small Island Removal Threshold: %d\n", islandThreshold);
    PRINT(MSG_NORMAL, "Layer Importance Threshold: %f\n", layerThreshold);
    PRINT(MSG_NORMAL, "Skeleton DT Threshold: %f\n", SKELETON_DT_THRESHOLD);
    PRINT(MSG_NORMAL, "Skeleton Saliency Threshold: %d\n", SKELETON_SALIENCY_THRESHOLD);
    PRINT(MSG_NORMAL, "Skeleton CCA Threshold: %d\n", SKELETON_ISLAND_THRESHOLD);
    PRINT(MSG_NORMAL, "Minimum object size: %d\n", MIN_OBJECT_SIZE);
    PRINT(MSG_NORMAL, "Threshold for sum of radii: %d\n", MIN_SUM_RADIUS);
    PRINT(MSG_NORMAL, "Minimal branch length: %d\n", MIN_PATH_LENGTH);
    PRINT(MSG_NORMAL, "\n\n-------- End of Configuration --------\n\n");
}




int main(int argc, char **argv) {
    FIELD<float> *f;
    Image *il;
    /* Parse options */
    if (argc != 2) {
        fstream fhelp("./doc/USAGE", fstream::in);
        cout << fhelp.rdbuf();
        fhelp.close();

        exit(-1);
    }
    Config config = Config(argv[1], NULL);
    setConfig(config);
    if(argc == 3){
        OUTPUT_FILE = argv[2];
    }

    PRINT(MSG_NORMAL, "Reading input file: %s\n", filename);
    f = FIELD<float>::read(filename); /* Read scalar field input */
    if (!f) {
        PRINT(MSG_ERROR, "Failed to read file.\n");
        exit(EXIT_FAILURE);
    }
    PRINT(MSG_NORMAL, "Done.\n");


    PRINT(MSG_VERBOSE, "Initializing Statistics Manager\n");


    il = new Image(f, islandThreshold, layerThreshold);
    IS_analyseImage("raw", il->im);
    il->removeIslands();
    IS_analyseImage("removed_islands", il->im);
    il->calculateImportance();
    il->removeLayers();
    IS_analyseImage("removed_layers", il->im);
    il->computeSkeletons();
    IS_stop();

    delete il;
    
    return 0;
}




