/*
	 * Constructor #3
	 *
	 * We know character probabilities. Input: pairs <character, probability>
	 *
	 * Here the alphabet is Huffman encoded.
	 *
	 * Note: all characters that will appear in the text must be included
	 * in P. If in doubt, assign probability 0 (such characters will get
	 * the longest codes)
	 *
	 */
	alphabet_encoder(vector<pair<char_type,double> >& P){

		sigma = P.size();
		enc_type = huffman;

		auto comp = [](node x, node y){ return x.second < y.second; };
		multiset<node,decltype(comp)> s(comp);

		//insert leaves
		for(auto it = P.begin();it!=P.end();++it)
			s.insert({{NULL,&it->first},it->second});

		//Huffman algorithm
		while(s.size()>1){

			//extract, copy and erase the 2 smallest elements
			auto min1 = new node(*s.begin());

			s.erase(s.begin());

			auto min2 = new node(*s.begin());

			s.erase(s.begin());

			double new_prob = min1->second + min2->second;
			pair<void*,void*> children = {min1,min2};

			s.insert({ children, new_prob });

		}

		node root = *s.begin();
		extract_codes(&root,{});

		root.free_memory();

	}
bool NerveTool::extract_fiberitems( FILE *sout , StringList& fibersinfo , String type , String& value ) {
	// parse value: x,y -> x,y -> x,y ...
	ClassList<StringList> chain;

	value.trim();
	while( !value.isEmpty() ) {
		String part;
		int idx = value.find( "->" );
		if( idx < 0 ) {
			if( chain.count() == 0 )
				return( false );

			part = value;
			value.clear();
		}
		else {
			part = value.getMid( 0 , idx );
			value.remove( 0 , idx + 2 );
			value.trim();

			if( value.isEmpty() )
				return( false );
		}

		// parse part
		StringList *z = new StringList;
		chain.add( z );
		if( !extract_codes( part , z ) ) {
			fprintf( sout , "wrong part=%s\n" , ( const char * )part );
			return( false );
		}

		// prohibit many-to-many		
		if( z -> count() > 1 && chain.count() > 1 ) {
			StringList& zp = chain.getRef( chain.count() - 2 );
			if( zp.count() > 1 )
				return( false );
		}
	}

	// chain of more than one
	if( chain.count() < 2 )
		return( false );

	// split chain
	int startChain = 0;
	int startChainCount = 0;
	for( int k = 0; k < chain.count(); k++ ) {
		StringList& z = chain.getRef( k );
		int zn = z.count();

		// starter
		if( k == 0 ) {
			startChainCount = zn;
			continue;
		}

		// many to one - split
		if( startChainCount > 1 ) {
			if( zn != 1 )
				return( false );

			addManyToOne( fibersinfo , type , chain.getRef( startChainCount ) , z.get( 0 ) );
			startChain = k;
			startChainCount = zn;
			continue;
		}

		// allow x -> y -> z as is
		if( zn == 1 ) {
			if( k == chain.count() - 1 ) {
				addSingleChain( fibersinfo , type , chain , startChain , k );
				break;
			}

			continue;
		}

		// x -> y -> x,y - split to x -> y and y -> x,y
		if( ( k - 1 ) > startChain ) {
			addSingleChain( fibersinfo , type , chain , startChain , k - 1 );
			startChain = k - 1;
			startChainCount = 1;
		}

		addOneToMany( fibersinfo , type , chain.getRef( startChain ).get( 0 ) , z );
		startChain = k;
		startChainCount = zn;
	}

	chain.destroy();

	return( true );
}