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

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

#ifndef STL_REFCOUNT_INCLUDED
#include <refcount>
#define STL_REFCOUNT_INCLUDED
#endif

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

#ifndef DP_SINGLETON_INCLUDED
#include <singleton>
#define DP_SINGLETON_INCLUDED
#endif

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

#ifndef MARKER_H_INCLUDED
#include "marker.h"
#endif

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

///////////////////////////////////////////////////////////////////////////
//
// Haplotype
//
// Concrete class representing a VALUE.  Haplotypes are sequences of
// marker values at specific loci along a chromosome.
//
///////////////////////////////////////////////////////////////////////////

class Haplotype {

    typedef std::vector<Marker>	container_type;

public:
    typedef typename container_type::value_type value_type;
    typedef typename container_type::size_type size_type;
    typedef typename container_type::difference_type difference_type;
    typedef typename container_type::const_iterator const_iterator;

    enum property_flags {
	NONE		= 0,
	LATENT		= (1 << 1),
	DISEASED	= (1 << 2),
	NORMAL		= (1 << 3)
    };
    typedef unsigned int property_t;
    
public:
    Haplotype(size_type = 0);
    
    template <class InputIterator>
    Haplotype(InputIterator, InputIterator);
    
public:
    // Container-like members.
    const_iterator	begin() const;
    const_iterator	end() const;
    size_type		size() const;
    const Marker	operator[](size_type) const;
    const_iterator	const_iterator_at(size_type) const;
    
public:
    // Returns the properties of the haplotype.
    property_t	Properties() const;

    // Set properties of the haplotype.
    void	SetProperties(property_t) const;

    // Returns true if haplotype is latent.
    bool	IsLatent() const;
    
    // Returns haplotype sub-segment [i, j).
    Haplotype	Substr(size_type, size_type) const;
    Haplotype	Substr(const_iterator, const_iterator) const;
    
    // Mutates the haplotype at the specified marker.
    void	Mutate(size_type, Marker);

    // Recombines the haplotype at the specified gap in the
    // specified direction.
    void	LeftRecombine(size_type, const Haplotype&);
    void	RightRecombine(size_type, const Haplotype&);

    // Mask haplotype outside of specified range.
    void	Mask(size_type, size_type);
    
    // Input haplotypes from streams.
    void	Read(istream&);
    bool	ReadDelimited(istream&, property_t = Haplotype::NONE,
			      char = '\n');

private:
    // Class representing haplotype value.
    struct HaplotypeValue : public rc_object {
	container_type loci;
	
	HaplotypeValue(size_type);
	HaplotypeValue(const container_type &);
    };
    
    rc_ptr<HaplotypeValue> _value;
};

bool		operator==(const Haplotype&, const Haplotype&);
bool		operator<(const Haplotype&, const Haplotype&);
ostream&	operator<<(ostream&, const Haplotype&);
istream&	operator>>(istream&, Haplotype&);


class HaplotypeProperties : public Singleton<HaplotypeProperties> {
public:
    typedef typename Haplotype::property_t property_t;

    void	Observed(const Haplotype&, property_t = Haplotype::DISEASED);
    void	SetProperties(const Haplotype&, property_t);

    property_t 	Properties(const Haplotype&) const;

protected:
    ~HaplotypeProperties() {}
    
private:
    typedef std::map<Haplotype, property_t> PropertyMap;

    PropertyMap _properties;
};

#include "haplotype_inline.h"

#endif // HAPLOTYPE_H_INCLUDED
