/* 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 SELFASSEMBLY_PLUGIN_H
#define SELFASSEMBLY_PLUGIN_H

#include <memory>
#include <set>
#include <unordered_set>
#include "Assembly.h"
#include "AnalyzerParameter.h"
#include "Sequence.h"
#include "SelfAssemblyDefines.h"

namespace SelfAssembly{
class Analyzer;
class EquilibriumForces;
}

namespace SelfAssembly{

class SelfAssemblyPlugin {

public:
	
	typedef Vector4 Color;
	typedef std::unordered_set<int> IPriorities;
	typedef std::unordered_set<int> BlockSet;
	typedef std::vector<BlockSet> BlockSets;
	
private: //Only for internal usage
	typedef std::pair<int,int> Interface;
	typedef std::vector< Interface > Interfaces;
	
public:
	
	explicit SelfAssemblyPlugin();
	virtual ~SelfAssemblyPlugin();

	//IO
	void saveBlocksFile(SelfAssembly::Assembly &a, std::string *_fileName=NULL);
	void saveInterfaceFile(const Interfaces &ifs, std::string* _fileName=NULL);
	
	void loadBlocksFile(std::string *fileName=NULL, bool overwrite=false);
	void loadInterfacesFile(std::string *fileName=NULL);

	bool loadSequence( std::string* _fileName=NULL );
	bool writeSequence( const SelfAssembly::AnalyzerParameter& ap, std::string* _fileName=NULL );

	void clearAssembly();

	//Analyze
	void staticAnalysis(const SelfAssembly::AnalyzerParameter& ap,
						 bool segmentation=false,
						 bool _debug=false);
	
	int sequenceAnalysis(const SelfAssembly::AnalyzerParameter& ap,
						  bool _removeUnusedChains=false,
						  bool _greedyHeuristic=false,
						  std::vector<int> *_seq=NULL,
						  const IPriorities *_priorities=NULL,
						  bool _topDown=false,
						  bool _debug=false,
						  bool _storeVariables=false);
	
	//generate sequences
	void generateZOrderSequence( std::vector<int>& seq );
	void generateFloodfillSequence( std::vector<int>& seq );
	void computePriorities( const SelfAssembly::AnalyzerParameter& ap, IPriorities& ip );
	void enableBlocks(const std::vector<int> &blockIdxs );

private:

	void disableUnusedChains( const SelfAssembly::EquilibriumForces* _forces, SelfAssembly::Assembly* _assembly );
	void disabledNeighborsToQueue(SelfAssembly::Assembly &a,
								  BlockSet &nextBlocks,
								  bool _topDown=false,
								  const BlockSet *bs=NULL);
	
	void ifsPrioritiesToBlockset(const SelfAssembly::Assembly &a,
								  const IPriorities& ip,
								  BlockSets &bs,
								 const SelfAssembly::AnalyzerParameter& ap);

	
private:
	
	SelfAssembly::Assembly* assembly_;	
	SelfAssembly::EquilibriumForces* lastForces_;
	bool interfacesLoaded_;
	SelfAssembly::Sequence lastSequence_;
	std::string lastDir_;
	BlockSet priorities_;
};

}//namespaces

#endif
