open Sast
open Types
open Printf

exception NotFinished


let string_of_forbindings (bindings: (string*int) list) =
  List.fold_left (fun str (vname,vval) -> 
                    Printf.sprintf "%s=%d %s" vname vval str ) "" bindings

let string_of_varbindings (bindings: float StringMap.t) =
  StringMap.fold (fun vname vval str -> 
                    Printf.sprintf "%s=%.2f %s" vname vval str ) bindings ""

let rec string_of_int_list intl delim = match intl with
    [] -> ""
  | [x] -> string_of_int x
  | x :: li -> (string_of_int x) ^ delim ^ (string_of_int_list li delim)

let rec string_of_f_list intl delim f = match intl with
    [] -> ""
  | [x] -> (f x)
  | x :: li -> (f x) ^ delim ^ (string_of_f_list li delim f)

let string_of_float_array farray =
  "["^(string_of_f_list (Array.to_list farray) "," string_of_float )^"]"

let string_of_neuronvals faa =
  "["^(string_of_f_list (Array.to_list faa) ";" string_of_float_array )^"]"

let string_of_type = function
    Types.Int -> "int"
  | Types.Matrix(intl) -> (string_of_int_list intl "x") ^ " matrix"
  | Types.MatrixUnknownSize -> "unknown-sized matrix"

let rec string_of_expr (expr,t) =
  (string_of_exprd expr) ^ " of " ^ (string_of_type t )

and string_of_exprd = function
   Sast.Float(v) -> (string_of_float v)^".f"
 | Sast.Unop(op,x1) -> 
     let s1 = string_of_expr x1 in
     let sop = match op with
         Cos -> " cos "
       | Sin -> " sin "
       | Exp -> " exp "
       | Negate -> " - "
     in 
       sop ^ "(" ^ s1 ^ ")"
 | Sast.Binop(x1,op,x2) -> 
     let s1 = string_of_expr x1 in
     let s2 = string_of_expr x2 in
     let sop = match op with
         Add -> " + "
       | Sub -> " - "
       | Mul -> " * "
       | Div -> " / "
       | Pow -> " ^ "
     in
     "(" ^ s1 ^ sop ^ s2 ^ ")"
 | Sast.Intgr(i) -> (string_of_int i)
 | Sast.SizeOf(_,_) ->"SizeOf"
 | Sast.Id(vn) -> "Id "^vn
 | Sast.NeuronRef(gsid,name,indl) ->
     Printf.sprintf "%d:%s[%s]" gsid
       name (string_of_indices indl)
 | Sast.ActRef(_,name,_,_) ->"ActRef:"^name
 | Sast.WghtRef(_,name,_) ->"WghtRef:"^name
 | Sast.Conv(x1,x2) ->
     let s1 = string_of_expr x1 in
     let s2 = string_of_expr x2 in
       Printf.sprintf "(%s)**(%s)" s1 s2
 | Sast.Span(_,_,_) ->"Span"
 | Sast.ForExpr(_,_) ->"ForExpr"
 | Sast.Param(pnum,[]) -> 
      Printf.sprintf "$%d" pnum 
 | Sast.Param(pnum,dlist) -> 
      Printf.sprintf "$%d[%s]" pnum (string_of_indices dlist)
 | Sast.ExtNeuron(gsid,mname,mind,nname,nind) -> 
      Printf.sprintf "ExtNeuron %d %s[%s].%s[%s]" gsid
        mname (string_of_indices mind)
        nname (string_of_indices nind) 

and string_of_indices dlist = 
  (List.fold_left 
     (fun str x -> 
        (match str with ""->string_of_exprd x 
           | str -> str^","^(string_of_exprd x))) "" dlist)

let rec string_of_forlist = function
    [] -> ""
  | ForExpr( id, Span( e1, e2, e3 ) ) :: li ->
      let str = Printf.sprintf " for %s=[%s:%s:%s]" 
                  id (string_of_exprd e1)
                     (string_of_exprd e2)
                     (string_of_exprd e3)
      in str ^ (string_of_forlist li)
  | _ -> "(invalid format?)"

let string_of_synap k syn = match syn with
    { sdest = Param(pnum,mapl); sexpr=sexpr; sfor=[] } ->
      ( Printf.sprintf "[%d] $%d << %s;\n" 
          k pnum
          (string_of_expr sexpr) : string )
  | { sdest = Param(pnum,dlist); sexpr=sexpr; sfor=sfor } ->
      ( Printf.sprintf "[%d] $%d[%s] << %s%s;\n" 
          k pnum
          (List.fold_left 
             (fun str x -> (match str with 
                                ""->string_of_exprd x 
                              | str -> str^","^(string_of_exprd x))) "" dlist)
          (string_of_expr sexpr) 
          (string_of_forlist sfor)
      )
  | { sdest=sdest; sexpr=sexpr; sfor=sfor; } ->
      ( Printf.sprintf "[%d] %s << %s%s;\n" 
          k
          (string_of_exprd sdest)
          (string_of_expr sexpr) 
          (string_of_forlist sfor)
      )

let string_of_io = function
  SpaceDelimFile(str,_) -> "SpaceDelimFile:"^str
| InPpm(str,rtime) -> "InPpm " ^ str^" : "^(string_of_int rtime)
| OutPpmSeq(str) -> "OutPpmSeq " ^ str


let string_of_param k pam = 
  let inoutstr = match pam.pa_ptype with
      InParam -> "in"
    | OutParam -> "out"
  in 
  let dtypestr = match pam.pa_data with
      FloatArray(_) -> "FloatArray"
    | ImageC3(_) -> "ImageC3"
    | Unallocated -> "Unallocated"
  in
    Printf.sprintf "%s %d (%s|%s) %s\n" 
      inoutstr
      pam.pa_num
      (Sast.string_of_t pam.pa_type) dtypestr 
      (string_of_io pam.pa_io)

let string_of_neuron gsid n =
  Printf.sprintf "%s.%s(=%d)[(%d)] of %s\n" n.n_mname n.n_name gsid 
    (Array.length n.v)
    (string_of_type n.t)

let string_of_afundef gsid 
      { af_name=name; af_invar=invar; af_params=fparams; af_expr=expr } =
  Printf.sprintf "%d %s(%s)=%s" gsid name
    (List.fold_left 
       (fun str (vname,fval)->
          Printf.sprintf 
            "%s%s=%.2f"
            (match str with "" -> "" | _ -> str^",")
            vname fval) "" fparams)
    (string_of_expr expr)

let string_of_program p =
  let s = IntMap.fold 
            (fun k syn str -> (string_of_synap k syn) ^ str ) p.syn "" 
  in
  let pa = IntMap.fold 
             (fun k pam str -> (string_of_param k pam) ^ str ) p.pparams ""
  in
  let n = IntMap.fold 
             (fun k n str -> (string_of_neuron k n) ^ str ) p.pneurons ""
  in
    "_______________________\n"^
    "Program:\n"^
    ".......................\n"^
    "Synapses:\n" ^ s ^ "\n" ^ 
    "Params:\n" ^ pa ^"\n"^
    "Neurons:\n" ^ n ^"\n"^
    "=======================\n"
