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

#ifndef STL_MAP_INCLUDED
#include <map>
#define STL_MAP_INCLUDED
#endif

#ifndef STL_TRIPLET_INCLUDED
#include <triplet>
#define STL_TRIPLET_INCLUDED
#endif

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

#ifndef GEOMETRIC_H_INCLUDED
#include "geometric.h"
#endif

#ifndef HAPLOTYPE_H_INCLUDED
#include "haplotype.h"
#endif

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

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

class HDictionary;

///////////////////////////////////////////////////////////////////////////
//
// Probability
//
// Concrete Strategy class for calculating probabilities associated with
// haplotypes.
//
///////////////////////////////////////////////////////////////////////////

class Probability {
public:
    typedef Haplotype::size_type size_type;

public:
    Probability(Geometric, HDictionary*, probability,
		probability, probability,
		size_type, size_type, size_type,
		const string& = string(),
		const string& = string(),
		const string& = string(),
		bool = false,
		bool = false);
    
    bool	Verbose() const;

    size_type	LeftMask() const;
    size_type	RightMask() const;
    
    bool	PossibleMutation(const Haplotype&, const Haplotype&) const;
    unsigned int MutationJump(size_type) const;

    probability	P(const Haplotype&, const Haplotype&, size_type) const;
    probability	P_mutation(const Haplotype&, const Haplotype&) const;
    probability	P_recombination(const Haplotype&, const Haplotype&,
				size_type) const;

    /*
     * Return -log(P...).
     */
    log_probability log_P(const Haplotype&, const Haplotype&, size_type) const;
    log_probability log_P_mutation(const Haplotype&, const Haplotype&) const;
    log_probability log_P_recombination(const Haplotype&, const Haplotype&,
					size_type) const;
    
private:
    probability	P_mutation(const Haplotype&, const Haplotype&,
			   size_type) const;
    probability	P_left_recombination(const Haplotype&, const Haplotype&,
				     size_type, size_type) const;
    probability	P_right_recombination(const Haplotype&, const Haplotype&,
				      size_type, size_type) const;
    
    probability	P_mutation_at_k(size_type) const;
    probability	P_recombination_at_k(size_type) const;
    
    typedef std::vector<unsigned int> JumpVector;
    typedef std::vector<probability> ProbVector;
    typedef std::triplet<Haplotype, Haplotype, size_type> Triplet;

    mutable std::map<Triplet, log_probability> log_prob_cache;
    Geometric		_distribution;
    HDictionary*	_dictionary;
    probability		_ibd;		// relative probability of ibd
    probability		_gamma;		// relative probability of a mutation
    bool		_verbose;
    bool		_no_recomb_sum;
    size_type		_left_mask;
    size_type		_right_mask;
    JumpVector		_Jump_at_k;
    ProbVector		_P_mutation_at_k;
    ProbVector		_P_recombination_at_k;
    std::map<Haplotype, probability> _root_prior;
};

#include "probability_inline.h"

#endif /* PROBABILITY_H_INCLUDED */
