open Types
open Bigarray

let t1of3 (x,_,_) = x
let t2of3 (_,x,_) = x
let t3of3 (_,_,x) = x

module StringMap = Map.Make(String)

module IntMap = Map.Make(struct type t = int 
        let compare x y = Pervasives.compare x y end)

let intMapCount m = IntMap.fold (fun k d a -> a+1) m 0


type operator = Add | Sub | Mul | Div | Pow
type operator1 = Exp | Sin | Cos | Negate

type mod_ref = string 
type var_ref = string

type expr_detail =
    Binop of expr * operator * expr
  | Unop of operator1 * expr
(*  | Exp of expr
  | Sin of expr
  | Negate of expr
  | Cos of expr *)
  | Float of float
  | Intgr of int
  | SizeOf of expr_detail * int
  | Id of var_ref
  | ActRef of int * string * expr * (string * float) list
  | WghtRef of int * string * (string * float) list
  | Conv of expr * expr
  | Span of expr_detail * expr_detail * expr_detail
(*  | Begin
  | End *)
  | ForExpr of string * expr_detail
  | ExtNeuron of int * (* gsid *)
      mod_ref * expr_detail list * var_ref * expr_detail list
  | Param of int * expr_detail list 
  | NeuronRef of int * (* gsid *)
      string * expr_detail list (* was Indx *)
and
  expr = expr_detail * Types.t

type ptype = InParam | OutParam

type channel =
    OpenIn of in_channel
 |  OpenOut of out_channel
 |  Closed
type param_io = 
    SpaceDelimFile of string * channel
  | InPpm of string * int (* fname, time remaining *)
  | OutPpmSeq of string  (* fname pattern *)
    
type param_data =
    FloatArray of float array
  | ImageC3 of (int,Bigarray.int8_unsigned_elt,Bigarray.c_layout) Array3.t
  | Unallocated


type param_def = {
   pa_num: int;
   pa_type: Types.t;
   pa_ptype: ptype;
   pa_io: param_io;
   pa_data: param_data;
}
type actfun_def = {
   af_gsid: int; (* global symbol id *)
   af_name: string;
   af_invar: string;
   af_params: (string * float) list;
   af_expr: expr;
}
type kerfun_def = {
   kf_gsid: int; (* global symbol id *)
   kf_name: string;
   kf_indices: string list;
   kf_params: (string * float) list;
   kf_expr: expr;
}
type modtrix = {
   mt_dims: int list;
}
type neuron = {
  t: Types.t;
  v: float array array; (* 0 = working value, 1 = curr val, 2 = t-1 value *)
  n_name: string; (* only needed for debug *)
  n_mname: string; (* only needed for debug *)
}

type synapse = {
   sdest : expr_detail; (* ExtNeuron, Param, or NeuronRef *)
   sexpr : expr;
   sfor  : expr_detail list;
}

type prog = {
   syn: synapse IntMap.t; (* what is the key? pnum of param? *)
   pneurons: neuron IntMap.t; (* key is gsid *)
   pparams: param_def IntMap.t;
   actfuns: actfun_def IntMap.t;
   kerfuns: kerfun_def IntMap.t;
}
type neuro_type = 
    InputNeuron | OutputNeuron | InterNeuron

type neuro_def = string * int * Types.t * neuro_type

type neuro_def_match =
    NeuroDefMatch of neuro_def
  | NoNeuroDefMatch

type mod_def = {
     m_name: string;
     m_inputs: neuro_def list;
     m_outputs: neuro_def list;
     m_neurons: neuro_def list; (* inter-neurons *)
     (*m_moddecls: mod_def list; *)
     m_synaps: synapse list; (* ExtNeuron or Neuron only - list just for debug purposes *) 
}

let string_of_t = function
  Types.Int -> "Int"
| Types.Matrix( li ) -> 
        "Matrix " ^ ( List.fold_left 
        (fun str i -> match str with "" -> string_of_int i |
                                     str -> str ^ "x" ^ string_of_int i ) "" li)
| Types.MatrixUnknownSize -> "Matrix Unknown Size"

let print_t t = print_endline (string_of_t t)
