/* key.h
 *
 * Originally borrowed from Dan's implementation of Collins' Model 1. 
 *
 * $Id: key.h,v 1.5 2008/05/08 15:12:53 post Exp $
 */

#ifndef KEY_H
#define KEY_H

#include <map>
#include <string>
#include <iostream>
#include <fstream>
#include <cstdio>

#include "globals.h"

/* #define h(X) ((size_t) X) */
//#define i(X) (X)

//////////////////////////////////////////////////////////////////////////
////////////// pc

// dist for generating left and right children
// three levels of backoff: pc1 pc2 pc3
// all three share predicted event type hs_c

// pc1

class hs_c1 {
 public:
 hs_c1(char ip, char ih, char *ihhw, char ihht, char ileft, char iadj, char iverb) :
  p(ip), hhw(ihhw), hht(ihht), left(ileft), adj(iadj), verb(iverb) { h = ih;}
  char p; char h; char *hhw; char hht; char left; char adj; char verb;
};
struct hash_hs_c1 {
  size_t operator()(const hs_c1&s) const {
    //hash<char*> h;
    hash<int> i;

    return (((size_t)s.hhw) ^
            i(s.p) ^
            (i(s.h) << 1) ^
            (i(s.hht) << 2) ^
            (i(s.left) << 3) ^
            (i(s.adj) << 4) ^
            (i(s.verb) << 5));
  }
};

struct eq_c1 { 
  bool operator()(hs_c1 i1, hs_c1 i2) const { 
    return (i1.hhw  ==      i2.hhw  &&
            i1.p  ==      i2.p &&
            i1.h  ==  i2.h      &&
            i1.hht  ==  i2.hht &&
            i1.left ==  i2.left &&
            i1.adj  ==  i2.adj &&
            i1.verb ==  i2.verb);

  } 
}; 
ostream& operator<< (ostream& ostr, const hs_c1& s);

/// pc2

class hs_c2 {
 public:
 hs_c2(char ip, char ih, char ihht, char ileft, char iadj, char iverb) :
  p(ip), hht(ihht), left(ileft), adj(iadj), verb(iverb) { h = ih; }
  char p; char h; char hht; char left; char adj; char verb;
};
struct hash_hs_c2 {
  size_t operator()(const hs_c2&s) const {
    hash<int> i;
    return (i(s.p) ^
            (i(s.h) << 1) ^
            (i(s.hht) << 2) ^
            (i(s.left) << 3) ^
            (i(s.adj) << 4) ^
            (i(s.verb) << 5));
  }
};
struct eq_c2 { 
  bool operator()(hs_c2 i1, hs_c2 i2) const { 
    return (i1.p  ==      i2.p &&
            i1.h  ==  i2.h      &&
            i1.hht  ==  i2.hht &&
            i1.left ==  i2.left &&
            i1.adj  ==  i2.adj &&
            i1.verb ==  i2.verb);

  } 
}; 
ostream& operator<< (ostream& ostr, const hs_c2& s);

/// pc3

class hs_c3 {
 public:
 hs_c3(char ip, char ih, char ileft, char iadj, char iverb) :
  p(ip), left(ileft), adj(iadj), verb(iverb) { h=ih; }
  char p; char h; char left; char adj; char verb;
};
struct hash_hs_c3 {
  size_t operator()(const hs_c3&s) const {
    hash<int> i;
    return (i(s.p) ^
            (i(s.h) << 1) ^
            (i(s.left) << 3) ^
            (i(s.adj) << 4) ^
            (i(s.verb) << 5));
  }
};
struct eq_c3 { 
  bool operator()(hs_c3 i1, hs_c3 i2) const { 
    return (i1.p  ==      i2.p &&
            i1.h  ==  i2.h      &&
            i1.left ==  i2.left &&
            i1.adj  ==  i2.adj &&
            i1.verb ==  i2.verb);

  } 
}; 
ostream& operator<< (ostream& ostr, const hs_c3& s);

// c

class hs_c {
 public:
 hs_c(char ic, char icht, char ipunc, char iconj) :
  c(ic), cht(icht), punc(ipunc), conj(iconj) {}
  char c; char cht; char punc; char conj;
};
struct hash_hs_c {
  size_t operator()(const hs_c&s) const {
    hash<int> i;
    return (i(s.c) ^
            (i(s.cht) << 1) ^
            (i(s.punc) << 2) ^
            (i(s.conj) << 3));
  }
};
struct eq_c { 
  bool operator()(hs_c i1, hs_c i2) const { 
    return (i1.c  ==      i2.c  &&
            i1.cht  ==      i2.cht &&
            i1.punc ==  i2.punc &&
            i1.conj ==  i2.conj);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_c& s);
typedef class hash_map<hs_c, float, hash_hs_c, eq_c> c_float_hash;

class c_c_bo {
 public:
 c_c_bo() : bo(0), u(0) {}
  c_float_hash p;
  float bo;
  int u;
};
typedef class hash_map<hs_c1, c_float_hash, hash_hs_c1, eq_c1> c1_c_float_hash;

typedef class hash_map<hs_c1, c_c_bo, hash_hs_c1, eq_c1> c1_c_bo_hash;
typedef class hash_map<hs_c2, c_c_bo, hash_hs_c2, eq_c2> c2_c_bo_hash;
typedef class hash_map<hs_c3, c_c_bo, hash_hs_c3, eq_c3> c3_c_bo_hash;

//////////////////////////////////////////////////////////////////////////
////////////// pcw

// dist for generating head word of new child
// three levels of backoff: pcw1 pcw2 pcw3
// all three share predicted event type hs_cw and c_cw_bo

// pcw1

class hs_cw1 {
 public:
 hs_cw1(char ip, char ih, char *ihhw, char ihht, char ileft, char iadj, char iverb,
        char ic, char icht, char ipunc, char iconj) :
  p(ip), hhw(ihhw), hht(ihht), left(ileft), adj(iadj), verb(iverb),
    c(ic), cht(icht), punc(ipunc), conj(iconj) { h=ih; }
  char p; char h; char *hhw; char hht; char left; char adj; char verb;
  char c; char cht; char punc; char conj;
};
struct hash_hs_cw1 {
  size_t operator()(const hs_cw1&s) const {
    //hash<char*> h;
    hash<int> i;
    return (((size_t)s.hhw) ^
            i(s.p) ^
            (i(s.h) << 1) ^
            (i(s.hht) << 2) ^
            (i(s.left) << 3) ^
            (i(s.adj) << 4) ^
            (i(s.verb) << 5) ^
            (i(s.c) << 6) ^
            (i(s.cht) << 7) ^
            (i(s.punc) << 8) ^ 
            (i(s.conj) << 9));
  }
};
struct eq_cw1 { 
  bool operator()(hs_cw1 i1, hs_cw1 i2) const { 
    return (i1.hhw  ==      i2.hhw  &&
            i1.p  ==      i2.p &&
            i1.h  ==  i2.h      &&
            i1.hht  ==  i2.hht &&
            i1.left ==  i2.left &&
            i1.adj  ==  i2.adj &&
            i1.verb ==  i2.verb &&
            i1.c  ==  i2.c &&
            i1.cht  ==  i2.cht &&
            i1.punc ==  i2.punc &&
            i1.conj   ==  i2.conj);

  } 
}; 
ostream& operator<< (ostream& ostr, const hs_cw1& s);

// pcw2

class hs_cw2 {
 public:
 hs_cw2(char ip, char ih, char ihht, char ileft, char iadj, char iverb,
        char ic, char icht, char ipunc, char iconj) :
  p(ip), hht(ihht), left(ileft), adj(iadj), verb(iverb),
    c(ic), cht(icht), punc(ipunc), conj(iconj) { h=ih; }
  char p; char h; char hht; char left; char adj; char verb;
  char c; char cht; char punc; char conj;
};
struct hash_hs_cw2 {
  size_t operator()(const hs_cw2&s) const {
    hash<int> i;
    return (i(s.p) ^
            (i(s.h) << 1) ^
            (i(s.hht) << 2) ^
            (i(s.left) << 3) ^
            (i(s.adj) << 4) ^
            (i(s.verb) << 5) ^
            (i(s.c) << 6) ^
            (i(s.cht) << 7) ^
            (i(s.punc) << 8) ^ 
            (i(s.conj) << 9));
  }
};
struct eq_cw2 { 
  bool operator()(hs_cw2 i1, hs_cw2 i2) const { 
    return (i1.p  ==      i2.p &&
            i1.h  ==  i2.h      &&
            i1.hht  ==  i2.hht &&
            i1.left ==  i2.left &&
            i1.adj  ==  i2.adj &&
            i1.verb ==  i2.verb &&
            i1.c  ==  i2.c &&
            i1.cht  ==  i2.cht &&
            i1.punc ==  i2.punc &&
            i1.conj   ==  i2.conj);

  } 
}; 
ostream& operator<< (ostream& ostr, const hs_cw2& s);

/// pcw3

class hs_cw3 {
 public:
 hs_cw3(char icht) :
  cht(icht) {}
  char cht;
};
struct hash_hs_cw3 {
  size_t operator()(const hs_cw3&s) const {
    hash<int> i;
    return (i(s.cht));
  }
};
struct eq_cw3 { 
  bool operator()(hs_cw3 i1, hs_cw3 i2) const { 
    return (i1.cht  ==      i2.cht);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_cw3& s);
typedef class hash_map<hs_cw3, float, hash_hs_cw3, eq_cw3> cw3_float_hash;

// cw

class hs_cw {
 public:
 hs_cw(char *ichw) :
  chw(ichw) {}
  char *chw;
};
struct hash_hs_cw {
  size_t operator()(const hs_cw&s) const {
    //hash<char*> h;
    return (size_t) s.chw;
  }
};
struct eq_cw { 
  bool operator()(hs_cw i1, hs_cw i2) const { 
    return (i1.chw  ==      i2.chw);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_cw& s);
typedef class hash_map<hs_cw, float, hash_hs_cw, eq_cw> cw_float_hash;

class c_cw_bo {     /* for backoff representation */
 public:
 c_cw_bo() : bo(0), u(0) {}
  cw_float_hash p;
  float bo;     /* backoff weight */
  int u;
};
typedef class hash_map<hs_cw1, cw_float_hash, hash_hs_cw1, eq_cw1> cw1_cw_float_hash;

typedef class hash_map<hs_cw1, c_cw_bo, hash_hs_cw1, eq_cw1> cw1_cw_bo_hash;
typedef class hash_map<hs_cw2, c_cw_bo, hash_hs_cw2, eq_cw2> cw2_cw_bo_hash;
typedef class hash_map<hs_cw3, c_cw_bo, hash_hs_cw3, eq_cw3> cw3_cw_bo_hash;

//////////////////////////////////////////////////////////////////////////
////////////// ph

// dist for generating head from parent
// three levels of backoff: ph1 ph2 ph3
// all three share predicted event type hs_h and c_h_bo

// ph1

class hs_h1 {
 public:
 hs_h1(char ip, char *ihhw, char ihht) :
  p(ip), hhw(ihhw), hht(ihht) {}
  char p; char *hhw; char hht;
};
struct hash_hs_h1 {
  size_t operator()(const hs_h1&s) const {
    //hash<char*> h;
    hash<int> i;
    return (((size_t) s.hhw) ^
            i(s.p) ^
            (i(s.hht) << 1));
  }
};
struct eq_h1 { 
  bool operator()(const hs_h1& i1, const hs_h1& i2) const { 
    return (i1.hhw  ==      i2.hhw  &&
            i1.p  ==      i2.p &&
            i1.hht  ==  i2.hht);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_h1& s);

// ph2

class hs_h2 {
 public:
 hs_h2(char ip, char ihht) :
  p(ip), hht(ihht) {}
  char p; char hht;
};
struct hash_hs_h2 {
  size_t operator()(const hs_h2& s) const {
    hash<int> i;
    return (i(s.p) ^
            (i(s.hht) << 1));
  }
};
struct eq_h2 { 
  bool operator()(const hs_h2& i1, const hs_h2& i2) const { 
    return (i1.p  ==      i2.p &&
            i1.hht  ==  i2.hht);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_h2& s);

// ph3

class hs_h3 {
 public:
 hs_h3(char ip) :
  p(ip) {}
  char p;
};
struct hash_hs_h3 {
  size_t operator()(const hs_h3& s) const {
    hash<int> i;
    return (i(s.p));
  }
};
struct eq_h3 { 
  bool operator()(const hs_h3& i1, const hs_h3& i2) const { 
    return (i1.p  ==      i2.p);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_h3& s);


// h

class hs_h {
 public:
  hs_h(int ih) 
    { h = ih; }
  char h;
};
struct hash_hs_h {
  size_t operator()(const hs_h& s) const {
    hash<int> i;
    return (i(s.h));
  }
};
struct eq_h { 
  bool operator()(const hs_h& i1, const hs_h& i2) const { 
    return (i1.h  ==      i2.h);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_h& s);
typedef class hash_map<hs_h, float, hash_hs_h, eq_h> h_float_hash;


class c_h_bo {
 public:
 c_h_bo() : bo(0), u(0) {}
  h_float_hash p;
  float bo;
  int u;
};
typedef class hash_map<hs_h1, h_float_hash, hash_hs_h1, eq_h1> h1_h_float_hash;

typedef class hash_map<hs_h1, c_h_bo, hash_hs_h1, eq_h1> h1_h_bo_hash;
typedef class hash_map<hs_h2, c_h_bo, hash_hs_h2, eq_h2> h2_h_bo_hash;
typedef class hash_map<hs_h3, c_h_bo, hash_hs_h3, eq_h3> h3_h_bo_hash;


//////////////////////////////////////////////////////////////////////////
////////////// pp

// dist for constituent priors
// two levels of backoff: pp1 pp2
// both share predicted event type hs_p and c_p

// pp1

class hs_pp1 {
 public:
 hs_pp1(char *ihhw, char ihht) :
  hhw(ihhw), hht(ihht) {}
  char *hhw; char hht;
};
struct hash_hs_pp1 {
  size_t operator()(const hs_pp1 &s) const {
    //hash<char*> h;
    hash<int> i;
    return (((size_t)s.hhw) ^
            (i(s.hht) << 1));
  }
};
struct eq_pp1 { 
  bool operator()(hs_pp1 i1, hs_pp1 i2) const { 
    return (i1.hhw  ==      i2.hhw  &&
            i1.hht  ==  i2.hht);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_pp1& s);
typedef class hash_map<hs_pp1, float, hash_hs_pp1, eq_pp1> pp1_float_hash;

// pp2

class hs_pp2 {
 public:
 hs_pp2(char ihht) :
  hht(ihht) {}
  char hht;
};
struct hash_hs_pp2 {
  size_t operator()(const hs_pp2 &s) const {
    hash<int> i;
    return (i(s.hht));
  }
};
struct eq_pp2 { 
  bool operator()(hs_pp2 i1, hs_pp2 i2) const { 
    return (i1.hht  ==  i2.hht);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_pp2& s);

// pp

class hs_pp {
 public:
 hs_pp(char ip) :
  p(ip) {}
  char p;
};
struct hash_hs_pp {
  size_t operator()(const hs_pp&s) const {
    hash<int> i;
    return (i(s.p));
  }
};
struct eq_pp { 
  bool operator()(hs_pp i1, hs_pp i2) const { 
    return (i1.p  ==      i2.p);
  } 
}; 
ostream& operator<< (ostream& ostr, const hs_pp& s);
typedef class hash_map<hs_pp, float, hash_hs_pp, eq_pp> pp_float_hash;

class c_pp_bo {
 public:
 c_pp_bo() : bo(0), u(0) {}
  pp_float_hash p;
  float bo;
  int u;
};
typedef class hash_map<hs_pp1, pp_float_hash, hash_hs_pp1, eq_pp1> pp1_pp_float_hash;

typedef class hash_map<hs_pp1, c_pp_bo, hash_hs_pp1, eq_pp1> pp1_pp_bo_hash;
typedef class hash_map<hs_pp2, c_pp_bo, hash_hs_pp2, eq_pp2> pp2_pp_bo_hash;

#endif
