/* This file is part of the source code for the following publication:
 * Assembling Self-Supporting Structures, Deuss et al., SIGGRAPH Asia 2014
 *
 * Copyright (C) 2014 Mario Deuss <mario.deuss@epfl.ch>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef ANALYZERPARAMETER_H
#define ANALYZERPARAMETER_H

#include "QPFactory.h"
#include <iostream>
#include <fstream>

namespace SelfAssembly{

class AnalyzerParameter{

public:

	unsigned int solverType;	//A type enumerated in QPFactory::QPType. Currently only Mosek is available.
	double blockTangLsqw;		//Weight on squared tangential part of internal forces, experimental
	double blockNormLsqw;		//Weight on squared normal part of internal forces, experimental
	double chainLsqw;			//Weight on squared chain force magnitude, experimental
	double chainL1w;			//Weight on chain force magnitude, (1-lambda) in equation (5)
	double chainL1Segw;			//Weight on chain force magnitude during quasi-arch extraction, (1-lambda) in equation (5)
	double chainChangew;		//Weight on chain force magnitude change. Applied only magnitudes which where 0 in the previous state, experimental
	bool irls;					//Do iteratively reweighted least-squares, not iteratively reweighted l1. Experimental
	double friction;			//Friction coefficient, alpha in constraint (4)
	double anchorSafety;		//Anchor safety bound, f^max in equation (8)
	double chainSafety;			//Chain safety bound, f^max_c in equation (9)
	double density;				//Material density. Computed for each input such that the average length of the gravity forces is one.
	bool fixSelectedInterfacesToZero;	//Selected interfaces are constrained to have zero forces acting across
	bool reweightL1Chains;		//Enable iterative reweighting on the chain force magnitudes
	bool reweightL1Interfaces;	//Enable iterative reweighting on the grouped variables for quasi-arch extraction s_I in equation (5) and (7)
	int minReweightIterations;	//Minimal number of reweighting iterations. -1 means iterate until maxReweightIterations or (||f_c||^p + ||s_I||^p), equation (5) without lambda, did not decrease
	int maxReweightIterations;	//Maximal number of reweighting iterations, see minReweightIterations
	double lp;					//parameter p for reweighting in equation (10)
	double coneMinimum;			//parameter t for quasi-arch flood-fill
	double interfaceScales;		//Geometric safety factor by which we downscale the interfaces
	int report;					//Amount of reported information. The smaller the less information
	bool nFixedHeuristic;		//If enabled, connected components which contains less than two fixed blocks are dropped during quasi-arch flood-fill
	bool radialHeuristic;		//If enabled, connected components of bounding box less than 1/10th of the full bounding box radius are dropped are dropped during quasi-arch flood-fill
	bool erosion;				//If enabled, blocks which do not connect two otherwise independent sets in the component are dropped during quasi-arch flood-fill
	bool singleHeuristic;		//If enabled, blocks which have only a single neighbor in component are dropped during quasi-arch flood-fill
	bool interfaceGroupSparsity; //If disabled, quasi-arch extraction minimizes only sum of normal component of forces, otherwise all components. experimental



	AnalyzerParameter():solverType(QPFactory::QPMOSEKT),
		blockTangLsqw(0.),
		blockNormLsqw(0.),
		chainLsqw(0.),
		chainL1w(1.),
		chainL1Segw(15.),
		chainChangew(0.),
		irls(false),
		friction(0.6),
		anchorSafety(MYINF),
		chainSafety(MYINF),
		density(2000.),
		fixSelectedInterfacesToZero(false),
		reweightL1Chains(false),
		reweightL1Interfaces(false),
		minReweightIterations(5),
		maxReweightIterations(5),
		lp(0.05),
		coneMinimum(0.0),
		interfaceScales(0.9),
		report(1),
		nFixedHeuristic(true),
		radialHeuristic(true),
		erosion(true),
		singleHeuristic(true),
		interfaceGroupSparsity(true){;}
	
public:

	bool store( const std::string& fileName ){
		std::ofstream file;
		file.open (fileName.c_str());
		if(!file.good()){ return false;}
		file << std::setprecision(16);
		file << *this;
		if(file.fail()){ return false; }
		file.close();
		return true;
	}

	bool load( const std::string& fileName ){
		std::ifstream file;
		file.open (fileName.c_str());
		if(!file.good()){ return false;}
		file >> (*this);
		if(file.fail()){ return false; }
		file.close();
		return true;
	}

	friend std::ostream& operator<<( std::ostream& out, const AnalyzerParameter& ap ){
		out << "solverType: " << ap.solverType;
		out << ",blockTangLsqw: " << ap.blockTangLsqw;
		out << ",blockNormLsqw: " << ap.blockNormLsqw;
		out << ",chainLsqw: " << ap.chainLsqw;
		out << ",chainL1w: " << ap.chainL1w;
		out << ",chainL1Segw: " << ap.chainL1Segw;
		out << ",chainChangew: " << ap.chainChangew;
		out << ",irls: " << ap.irls;
		out << ",friction: " << ap.friction;
		out << ",anchorSafety: " << ap.anchorSafety;
		out << ",chainSafety: " << ap.chainSafety;
		out << ",density: " << ap.density;
		out << ",fixSelectedInterfacesToZero: " << ap.fixSelectedInterfacesToZero;
		out << ",reweightL1Chains: " << ap.reweightL1Chains;
		out << ",reweightL1Interfaces: " << ap.reweightL1Interfaces;
		out << ",minReweightIterations: " << ap.minReweightIterations;
		out << ",maxReweightIterations: " << ap.maxReweightIterations;
		out << ",lp: " << ap.lp;
		out << ",coneMinimum: " << ap.coneMinimum;
		out << ",interfaceScales: " << ap.interfaceScales;
		out << ",report: " << ap.report;
		out << ",nFixedHeuristic: " << ap.nFixedHeuristic;
		out << ",radialHeuristic: " << ap.radialHeuristic;
		out << ",erosion: " << ap.erosion;
		out << ",singleHeuristic: " << ap.singleHeuristic;
		out << ",interfaceGroupSparsity: " << ap.interfaceGroupSparsity;
		return out;
	}

	friend std::istream& operator>>( std::istream& in, AnalyzerParameter& ap ){
		std::string s;
		in >> s; in >> ap.solverType;
		in >> s; in >> ap.blockTangLsqw;
		in >> s; in >> ap.blockNormLsqw;
		in >> s; in >> ap.chainLsqw;
		in >> s; in >> ap.chainL1w;
		in >> s; in >> ap.chainL1Segw;
		in >> s; in >> ap.chainChangew;
		in >> s; in >> ap.irls;
		in >> s; in >> ap.friction;
		in >> s; in >> ap.anchorSafety;
		in >> s; in >> ap.chainSafety;
		in >> s; in >> ap.density;
		in >> s; in >> ap.fixSelectedInterfacesToZero;
		in >> s; in >> ap.reweightL1Chains;
		in >> s; in >> ap.reweightL1Interfaces;
		in >> s; in >> ap.minReweightIterations;
		in >> s; in >> ap.maxReweightIterations;
		in >> s; in >> ap.lp;
		in >> s; in >> ap.coneMinimum;
		in >> s; in >> ap.interfaceScales;
		in >> s; in >> ap.report;
		in >> s; in >> ap.nFixedHeuristic;
		in >> s; in >> ap.radialHeuristic;
		in >> s; in >> ap.erosion;
		in >> s; in >> ap.singleHeuristic;
		in >> s; in >> ap.interfaceGroupSparsity;
		return in;
	}
};

}

#endif // ANALYZERPARAMETER_H
