/*
 * Copyright (c) 1999 Johnny C. Lam.
 * All rights reserved.
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  The author makes no representations
 * about the suitability of this software for any purpose.  It is
 * provided "as is" without express or implied warranty.
 */

// -*- C++ -*-

#ifndef PROFILE_H_INCLUDED
#define PROFILE_H_INCLUDED

#ifndef STL_GRAPH_INCLUDED
#include <graph>
#define STL_GRAPH_INCLUDED
#endif

#ifndef STD_IOSFWD_INCLUDED
#include <iosfwd>
#define STD_IOSFWD_INCLUDED
#endif

#ifndef STD_MEMORY_INCLUDED
#include <memory>
#define STD_MEMORY_INCLUDED
#endif

#ifndef STD_STRING_INCLUDED
#include <string>
#define STD_STRING_INCLUDED
#endif

#ifndef STL_UTILITY_INCLUDED
#include <utility>
#define STL_UTILITY_INCLUDED
#endif

#ifndef STL_VECTOR_INCLUDED
#include <vector>
#define STL_VECTOR_INCLUDED
#endif

#ifndef PATH_H_INCLUDED
#include "path.h"
#endif

#ifndef TYPES_H_INCLUDED
#include "types.h"
#endif

class SegmentProbability;
class HDictionary;
class Probability;
class PathStrategy;
class PathCriterion;

void	ProfileInit(int, char* [],
		    int&, unsigned int&, unsigned int&,
		    unsigned int&, unsigned int&,
		    string&,
		    string&, string&, bool&, bool&,
		    std::auto_ptr<SegmentProbability>&,
		    std::auto_ptr<HDictionary>&,
		    std::auto_ptr<Probability>&,
		    std::auto_ptr<PathStrategy>&,
		    std::auto_ptr<PathCriterion>&);

typedef stl_graph<Haplotype, log_probability>	MutationClade;
typedef stl_graph<int, Path>			LinkClade;

struct Link {
  int			from_clade, to_clade;
  log_probability	priority;

  Link(int f, int t, log_probability p)
    : from_clade(f), to_clade(t), priority(p)
  {}
};

template <class Graph>
class IsObserved {
public:
    IsObserved(const Graph *g)
	: _g(g) {}
    bool operator()(const graph_traits<Graph>::node_type &n) const {
	return !(_g->value(n).IsLatent());
    }

private:
    const Graph *_g;
};

bool	operator<(const Link &, const Link &);

std::istream& operator>>(std::istream&, std::pair<Haplotype, probability>&);

struct TreeProperties {
    MutationClade*	tree;
    MutationClade::node	root;
    unsigned int	root_count;
    log_probability	weight;
    unsigned int	overcount;
    unsigned int	subset_size;

    TreeProperties() {}
    TreeProperties(MutationClade* t, MutationClade::node r, unsigned int rc,
		   log_probability w, unsigned int oc, unsigned int ss)
	: tree(t), root(r), root_count(rc),
	  weight(w), overcount(oc), subset_size(ss) {}
};

int	PathsIndex(int, int);
void	LinkWithPaths(const MutationClade &, const MutationClade &,
		      std::vector<std::pair<Path, Path> > &,
		      unsigned int, Probability *, PathStrategy *, int);
void	ExplodeClade(MutationClade &, const LinkClade &,
		     const vector<MutationClade *> &, int);
void	AddPath(MutationClade &, const Path &, int);

graph_traits<MutationClade>::node_type
	PruneLatents(MutationClade &, graph_traits<MutationClade>::node_type);

void	PrintTreePathWeights(ostream &,
			     const MutationClade &,
			     const graph_traits<MutationClade>::node_type &,
			     graph_traits<MutationClade>::weight_type);

void	PrintRootedTree(ostream &, int, unsigned int, const TreeProperties&);

std::auto_ptr<MutationClade>
	FindBestRootedTree(const MutationClade&,
			   const graph_traits<MutationClade>::node_type&,
			   graph_traits<MutationClade>::node_type*,
			   graph_traits<MutationClade>::weight_type*,
			   node_map<graph_traits<MutationClade>::weight_type>*);

graph_traits<MutationClade>::weight_type
	StarCriterion(const MutationClade&,
		      const graph_traits<MutationClade>::node_type&,
		      const node_map<graph_traits<MutationClade>::weight_type>&);

void
TotalPath(const MutationClade&,
	  const graph_traits<MutationClade>::node_type&,
	  unsigned int, unsigned int*);

#endif // PROFILE_H_INCLUDED
