#ifndef LSTRING_H
#define LSTRING_H

#include <stdio.h>
#include <string>
#include <vector>
#include "UIBaseClass.h"

using namespace std;

enum line_label {RECURSION=0, 
		 ANGLE, 
		 THICKNESS,
		 AXIOM,
		 FZ_RULE, 
		 USER_RULE, 
		 STANDARD_RULE,
		 COMMENT};

enum single_line_label {REC_LINE=RECURSION,
			ANG_LINE=ANGLE,
			THICK_LINE=THICKNESS,
			AXIOM_LINE=AXIOM};
enum {single_line_label_num=4};

enum var_line_label {REC_VARIABLE=RECURSION,
		     ANG_VARIABLE=ANGLE,
		     THICK_VARIABLE=THICKNESS};

const int NumDoubleMutParams=29;
struct MutationParameters
{
  MutationParameters(
  unsigned int v_MaxMutTries     = 100,
  char   *v_DefaultNewRule       = "F",
  double v_pr_R                  = 0.1,
  double v_R_stdev               = 1,
  double v_pr_A                  = 0.1,
  double v_A_stdev               = 20,
  double v_pr_T                  = 0.2,
  double v_T_stdev               = 5,
  double v_pr_length_gain_brack  = 0.5,
  double v_pr_length_lose_brack  = 0.5,
  double v_length_stdev          = 5,
  double v_length_decr_stdev     = 0.05, 
  double v_pr_angle_gain_brack   = 0.5,
  double v_pr_angle_lose_brack   = 0.5,
  double v_angle_stdev           = 10,
  double v_angle_decr_stdev      = 5,
  double v_pr_thick_gain_brack   = 0.5,
  double v_pr_thick_lose_brack   = 0.5,
  double v_thick_decr_stdev      = 0.05,
  double v_pr_colour_gain_brack  = 0.5,
  double v_pr_colour_lose_brack  = 0.5,
  double v_pr_trope_gain_brack   = 0.5,
  double v_pr_trope_lose_brack   = 0.5,
  double v_tr_stdev              = 0.05,
  double v_pr_randrot_gain_brack = 0.5,
  double v_pr_randrot_lose_brack = 0.5,
  double v_randrot_stdev         = 0.1,
  double v_pr_add_or_del_rule    = 0.2,
  double v_pr_add_rule           = 0.5,
  double v_pr_add_to_rule        = 0.9,
  double v_new_brack_dist_stdev  = 1.5
  );
  unsigned long MaxMutTries;
  string DefaultNewRule;
  double ParamArr[NumDoubleMutParams];
  //shortcut references to the parameters
  double &pr_R;
  double &R_stdev;
  double &pr_A;
  double &A_stdev;
  double &pr_T;
  double &T_stdev; 
  double &pr_length_gain_brack;
  double &pr_length_lose_brack;
  double &length_stdev;
  double &length_decr_stdev; 
  double &pr_angle_gain_brack;
  double &pr_angle_lose_brack;
  double &angle_stdev;
  double &angle_decr_stdev;
  double &pr_thick_gain_brack;
  double &pr_thick_lose_brack;
  double &thick_decr_stdev; 
  double &pr_colour_gain_brack;
  double &pr_colour_lose_brack;
  double &pr_trope_gain_brack;
  double &pr_trope_lose_brack;
  double &tr_stdev;
  double &pr_randrot_gain_brack;
  double &pr_randrot_lose_brack;
  double &randrot_stdev;
  double &pr_add_or_del_rule;
  double &pr_add_rule;
  double &pr_add_to_rule;
  double &new_brack_dist_stdev;
};

class LlineClass 
{
 private:
  string     the_text;
  size_t     end_text;
  line_label marker;
 public:
  LlineClass(vector<LlineClass *> *the_list);
  LlineClass(vector<LlineClass *> *the_list, LlineClass *cpy);
  void                assign(char * const rule_in, line_label marker_in);
  void                assign(const string rule_in, line_label marker_in);
  inline const string text();
  inline void         set_marker(line_label marker_in);
  inline              line_label get_marker();
  inline size_t       info_length();
  inline char         first_char();
  inline char         char_num(int i);
  inline char         *rule_start();
  inline bool         has_value(size_t pos);
  bool                is_float();
  float               as_float();
  bool   within_round_brackets(size_t the_pos, size_t &b, size_t &a);
  bool   within_round_brackets(size_t the_pos);
  size_t matching_bracket(size_t the_pos);
  double assoc_param(const size_t the_pos, int& the_length);
  bool   increment(size_t &the_pos);
  bool   decrement(size_t &the_pos);
};

class Lstring
{
  //c'tor & d'tor  methods
 public:
  Lstring(UIClass *ptr, MutationParameters *mut_param);
  ~Lstring();
 private:
  void GenerateStdRules();
  void Clear();
public:
  void operator<<(string& p);
  void operator>>(string& out);

  
  Lstring &operator=(Lstring& lstr);
  bool Parse();
  bool Parse(s16 reclevel); 
  void mutate_General_Algorithm  ();
  void mutate_General_Parameter  ();
  void mutate_Variable           ();
  void mutate_AddRule            ();
  bool mutate_DeleteRule         ();
  void mutate_ChangeRuleDelete   ();
  void mutate_ChangeRuleAdd      ();
  void mutate_ChangeRuleParameter();
   
  //methods to extract information
  bool   Get_value        (unsigned long &current_string_pos, r32 &val);
  int    Get_RecursionChar(unsigned long &s_pos);
  bool          FinalStringExists   ();
  string        FormattedFinalString();
  int           FinalStringRecLev   ();
  int           FinalStringLength   ();
  unsigned char FinalStringChr      (unsigned int i);
  string get_axiom   ();
  float  get_ang     ();
  float  get_thick   ();
  float  get_fraction();
  int    get_lev     ();
  bool   growing     ();
  
  //internal methods
 private:
  bool allocate_new_rule_char(string &rule);
  void GenerateStdRule (char *the_rule);
  int get_LineNumber   (vector<LlineClass *>::iterator the_line);
  void SetStdRules     ();
  bool InsertVariable  (string &to_insert, var_line_label which);
  bool InsertAxiom     (string &to_insert);
  bool InsertUserRule  (string &to_insert);
  bool ReplaceVariable (const float  new_value, var_line_label which);
  bool ReplaceVariable (const int    new_value, var_line_label which);
  bool ReplaceVariable (const string new_value, var_line_label which);
  bool ReplaceAxiom    (string to_insert);
  bool ReplaceUserRule (string to_insert, LlineClass *to_replace);
  void SetRule         (LlineClass *the_rule, char the_pos);
  void SetRule         (LlineClass *the_rule, unsigned char the_pos);
  void SetRule         (LlineClass *the_rule);
  bool SetUserRule     (LlineClass *the_rule);
  bool UnsetUserRule   (LlineClass *the_rule);
  void DeleteUserRule  (LlineClass *to_delete);
  char pick_axiom_or_rule_char(const bool random_line, 
			       vector<LlineClass *>::iterator &ln_itr, 
			       int &char_pos);
  void InitString();
  bool FS_alloc(size_t mem);
  
  // variables
 private:
  UIClass* const       UIClassPtr;
  
  unsigned char        CountChar[128];

  unsigned char        *FinalString;
  unsigned int         FS_MemSize;
  unsigned int         FS_Lgth;
  int                  FS_Lev;

  vector<LlineClass *> line;
  vector<LlineClass *> StdRule;
  LlineClass           *DefaultStdRule;
  LlineClass           *RuleForChar[256];
  LlineClass           *line_ptr[single_line_label_num];

  string               user_rules;
  int                  num_axiom_and_rule_chars;
  bool                 valid_string;

  MutationParameters*  const MutParam;
};

#endif
