extern crate graphics;
extern crate time;
use piston_window::*;
use lang::*;
use model::*;
use std::cmp;
use terrain;
use std::collections::{HashMap};

pub fn render(gm: &mut GameState, v: &mut WindowState, w: &mut PistonWindow, e: &Input) {
   w.draw_2d(e, |c, g| {
      if !gm.alive {
         render_dead(gm, v, &c, g);
      } else {
         clear([0.8, 0.8, 0.8, 1.0], g);
         render_partitions(gm, v, &c, g);
         render_nav(gm, v, &c, g);
         if v.tab == "Map".to_string() {
            render_map(gm, v, &c, g);
            match gm.agent_engaged {
               Some(_) => { render_fight(gm, v, &c, g); }
               None => { render_chat(gm, v, &c, g); }
            }
         } else if v.tab == "Character".to_string() {
            render_character(gm, v, &c, g);
         } else if v.tab == "Inventory".to_string() {
            render_inventory(gm, v, &c, g);
         } else if v.tab == "Library".to_string() {
            render_library(gm, v, &c, g);
         } else if v.tab == "Quests".to_string() {
            render_quests(gm, v, &c, g);
         }
      }
   });
}

pub fn render_dead(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let aspect_y = v.f_height / 1000.0;
   let aspect_x = v.f_width / 1600.0;
   let aspect = if aspect_y >= aspect_x { aspect_y } else { aspect_x };
   let bg_texture = v.texture("startscreen.png".to_string());
   let t = c.transform
            .trans(0.0, 0.0)
            .scale(aspect, aspect);
   image(&bg_texture, t, g);

   let char_em = v.f_em;
   let char_height = 28.0;
   let char_height_lift = 20.0;
   let char_mid = v.f_halfwidth();
   let char_base = v.f_height - 3.0 * v.f_em;

   let yad = "YOU ARE DEAD";
   let yad_left = char_mid - 6.0 * v.f_em;
   if (yad_left - 75.0) <= v.cursor[0] && v.cursor[0] < (yad_left + 9.0 * char_em) &&
      (char_base - char_height - 15.0) <= v.cursor[1] && v.cursor[1] < (char_base + 20.0) {
      match v.dead_tab.clone() {
         DeadTab::None => {
            for oxi in -2..3 {
            for oyi in -2..3 {
               let transform = c.transform.trans(yad_left + (oxi as f64), char_base + (oyi as f64));
               text::Text::new_color([1.0, 0.6, 0.6, 1.0], (char_em as u32)).draw(
                  yad,
                  &mut v.macondo,
                  &c.draw_state,
                  transform, g
               );
            }}

            let mut kill_click = false;
            if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
               v.dead_tab = DeadTab::Memorial;
               kill_click = true;
            }}
            if kill_click { v.clicked = None; }
         }
         _ => {}
      }
   }
   let transform = c.transform.trans(yad_left+1.0, char_base+1.0);
   text::Text::new_color([1.0, 0.2, 0.2, 1.0], (char_em as u32)).draw(
      yad,
      &mut v.macondo,
      &c.draw_state,
      transform, g
   );
   let transform = c.transform.trans(yad_left, char_base);
   text::Text::new_color([0.7, 0.1, 0.1, 1.0], (char_em as u32)).draw(
      yad,
      &mut v.macondo,
      &c.draw_state,
      transform, g
   );

   let ng = "New Game";
   let ng_left = v.f_width - 13.0 * v.f_em;
   let ng_base = 2.5 * char_height;
   if (ng_left - 75.0) <= v.cursor[0] && v.cursor[0] < (ng_left + 9.0 * char_em) &&
      (ng_base - char_height - 15.0) <= v.cursor[1] && v.cursor[1] < (ng_base + 20.0) {
      match v.dead_tab.clone() {
         DeadTab::None => {
            for oxi in -2..3 {
            for oyi in -2..3 {
               let transform = c.transform.trans(ng_left + (oxi as f64), 2.5 * char_height + (oyi as f64));
               text::Text::new_color([0.6, 0.6, 1.0, 0.8], (char_em as u32)).draw(
                  ng,
                  &mut v.macondo,
                  &c.draw_state,
                  transform, g
               );
            }}

            let mut kill_click = false;
            if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
               v.dead_tab = DeadTab::New(Some("vagabond".to_string()));
               kill_click = true;
            }}
            if kill_click { v.clicked = None; }
         }
         _ => {}
      }

   }
   let transform = c.transform.trans(ng_left + 1.0, 2.5 * char_height + 1.0);
   text::Text::new_color([0.4, 0.4, 0.8, 1.0], (char_em as u32)).draw(
      ng,
      &mut v.macondo,
      &c.draw_state,
      transform, g
   );
   let transform = c.transform.trans(ng_left, 2.5 * char_height);
   text::Text::new_color([0.2, 0.2, 1.0, 1.0], (char_em as u32)).draw(
      ng,
      &mut v.macondo,
      &c.draw_state,
      transform, g
   );

   let lg = "Load Game";
   let lg_left = v.f_width - 13.0 * v.f_em;
   let lg_base = 4.0 * char_height + char_height_lift;
   if (lg_left-75.0) <= v.cursor[0] && v.cursor[0] < (lg_left + 9.0 * char_em) &&
      (lg_base - char_height - 15.0) <= v.cursor[1] && v.cursor[1] < (lg_base + 20.0) {
      match v.dead_tab {
         DeadTab::None => {
            for oxi in -2..3 {
            for oyi in -2..3 {
               let transform = c.transform.trans(ng_left + (oxi as f64), 4.0 * char_height + char_height_lift + (oyi as f64));
               text::Text::new_color([0.6, 0.6, 1.0, 0.8], (char_em as u32)).draw(
                  lg,
                  &mut v.macondo,
                  &c.draw_state,
                  transform, g
               );
            }}

            let mut kill_click = false;
            if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
               v.dead_tab = DeadTab::Load(None, 0);
               kill_click = true;
            }}
            if kill_click { v.clicked = None; v.load_saves(); }
         }
         _ => {}
      }
   }
   let transform = c.transform.trans(ng_left + 1.0, 4.0 * char_height + char_height_lift + 1.0);
   text::Text::new_color([0.4, 0.4, 0.8, 1.0], (char_em as u32)).draw(
      lg,
      &mut v.macondo,
      &c.draw_state,
      transform, g
   );
   let transform = c.transform.trans(ng_left, 4.0 * char_height + char_height_lift);
   text::Text::new_color([0.2, 0.2, 1.0, 1.0], (char_em as u32)).draw(
      lg,
      &mut v.macondo,
      &c.draw_state,
      transform, g
   );

   let box_left = char_em * 3.0;
   let box_high = char_em * 3.0;
   match v.dead_tab.clone() {
      DeadTab::None => {}
      DeadTab::Memorial => {
         let new_border = graphics::Rectangle::new_border([1.0, 1.0, 0.4, 1.0], 0.7).color([0.8, 0.8, 0.8, 0.95]);
         new_border.draw([
            char_em*1.5, char_em*1.5, v.f_width-char_em*3.0, v.f_height-char_em*3.0
         ], &c.draw_state, c.transform, g);

         let x_left = v.f_width - 2.5*char_em;
         let x_top = 1.0 * char_em;
         let x_cross = 1.5 * char_em;
         rectangle([1.0, 1.0, 0.4, 1.0],
            [x_left, x_top, x_cross, x_cross],
                  c.transform, g);

         let mem = format!("Here lies the remains of {} the {}", gm.agent_name, gm.agent_class);
         let transform = c.transform.trans(box_left, box_high + char_height);
         text::Text::new_color([0.2, 0.2, 0.4, 1.0], ((char_em * 1.5) as u32)).draw(
            mem.as_str(),
            &mut v.macondo,
            &c.draw_state,
            transform, g
         );

         let far_left = char_em*1.5;
         let far_right = v.f_width - char_em*1.5;
         let toofar_bot = v.f_height - char_em*1.5;
         let far_bot = toofar_bot - 6.0 * char_height;
         let far_top = char_em*7.5;
         let max_width = far_right - far_left;
         let max_height = far_bot - far_top;

         let mut texname = "avatar_".to_string();
         texname.push_str(gm.agent_class.as_str());
         texname.push_str(".png");
         let av_texture = v.texture(texname);

         let span = if max_width>max_height { max_height } else { max_width };
         let aspect = span / 512.0;
         let new_left = far_left + (max_width - span)/2.0;

         let t = c.transform
                  .trans(new_left, far_top)
                  .scale(aspect, aspect);
         image(&av_texture, t, g);

         if x_left <= v.cursor[0] && v.cursor[0] < (x_left + x_cross) &&
            x_top <= v.cursor[1] && v.cursor[1] < (x_top + x_cross) {
            let mut kill_click = false;
            if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
               v.dead_tab = DeadTab::None;
               kill_click = true;
            } }
            if kill_click { v.clicked = None; }
         }
      }
      DeadTab::New(sel) => {
         let new_border = graphics::Rectangle::new_border([1.0, 0.4, 0.4, 1.0], 0.7).color([0.8, 0.8, 0.8, 0.95]);
         new_border.draw([
            char_em*1.5, char_em*1.5, v.f_width-char_em*3.0, v.f_height-char_em*3.0
         ], &c.draw_state, c.transform, g);

         let transform = c.transform.trans(box_left, box_high + char_height);
         text::Text::new_color([0.2, 0.2, 1.0, 1.0], ((char_em * 1.5) as u32)).draw(
            "Select a Class",
            &mut v.macondo,
            &c.draw_state,
            transform, g
         );

         let notch_high = box_high + 2.0 * char_height;

         for ci in 0..gm.class_list.len() {
            let classname = gm.class_list[ci].clone();

            let mut active = false;
            if box_left <= v.cursor[0] && v.cursor[0] < (box_left + 12.0 * char_em) &&
               (notch_high + (ci as f64) * 1.6 * char_height) <= v.cursor[1] && v.cursor[1] < (notch_high + (ci as f64) * 1.6 * char_height + 1.2*char_height) {
               active = true;

               let mut kill_click = false;
               if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
                  v.dead_tab = DeadTab::New(Some(classname.clone()));
                  kill_click = true;
               } }
               if kill_click { v.clicked = None; }
            }

            let cls_box_colour = if sel.is_some() && sel.clone().unwrap()==classname { [0.7, 0.7, 1.0, 1.0] }
                else if active { [0.4, 0.4, 1.0, 1.0] } else { [1.0, 1.0, 1.0, 1.0] };
            rectangle(cls_box_colour,
               [box_left, notch_high + (ci as f64) * 1.6 * char_height, 12.0 * char_em, 1.2*char_height],
             c.transform, g);

            let (mut r,mut y,mut b) = gm.from_class( gm.class_list[ci].clone() );
            for clsi in 0..3 {
               let mut colour = [1.0, 1.0, 1.0, 1.0];
               if r>0 { colour = [1.0, 0.4, 0.4, 1.0]; r -= 1; }
               else if y>0 { colour = [1.0, 1.0, 0.4, 1.0]; y -= 1; }
               else if b>0 { colour = [0.4, 0.4, 1.0, 1.0]; b -= 1; }

               rectangle(colour,
               [box_left + (clsi as f64) * char_em, notch_high + (ci as f64) * 1.6 * char_height, char_em, 1.2*char_height],
                c.transform, g);
            }

            let transform = c.transform.trans(box_left + 5.0 * char_em, notch_high + (ci as f64) * 1.6 * char_height + 24.0);
            text::Text::new_color([0.1, 0.1, 0.1, 1.0], (char_em as u32)).draw(
               gm.class_list[ci].as_str(),
               &mut v.macondo,
               &c.draw_state,
               transform, g
            );
         }

         let far_left = box_left + 12.0 * char_em;
         let far_top = box_high;
         let far_right = v.f_width - char_em*1.5;
         let toofar_bot = v.f_height - char_em*1.5;
         let far_bot = toofar_bot - 6.0 * char_height;
         let max_width = far_right - far_left;
         let max_height = far_bot - far_top;

         match sel {
            Some(classname) => {
               let mut texname = "avatar_".to_string();
               texname.push_str(classname.as_str());
               texname.push_str(".png");
               let av_texture = v.texture(texname);

               let span = if max_width>max_height { max_height } else { max_width };
               let aspect = span / 512.0;
               let new_left = far_left + (max_width - span)/2.0;

               let t = c.transform
                      .trans(new_left, box_high)
                      .scale(aspect, aspect);
               image(&av_texture, t, g);

               rectangle([0.4, 0.4, 1.0, 1.0],
                  [new_left, toofar_bot - 5.0*char_height, span, 4.0*char_height],
                  c.transform, g);

               let transform = c.transform.trans(new_left + span / 2.0 - 4.0 * char_em, toofar_bot - 2.3*char_height);
               text::Text::new_color([1.0, 1.0, 1.0, 1.0], (2.0*char_em) as u32).draw(
                  "Confirm",
                  &mut v.macondo,
                  &c.draw_state,
                  transform, g
               );

               if new_left <= v.cursor[0] && v.cursor[0] < (new_left + span) &&
                  (toofar_bot - 5.0*char_height) <= v.cursor[1] && v.cursor[1] < (toofar_bot - 5.0*char_height + 4.0*char_height) {

                  let mut kill_click = false;
                  if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
                     v.dead_tab = DeadTab::None;
                     gm.newgame(classname.clone());
                     kill_click = true;
                  } }
                  if kill_click { v.clicked = None; }

               }
            }
            None => {}
         }

         let x_left = v.f_width - 2.5*char_em;
         let x_top = 1.0 * char_em;
         let x_cross = 1.5 * char_em;
         rectangle([1.0, 0.4, 0.4, 1.0],
            [x_left, x_top, x_cross, x_cross],
                  c.transform, g);

         if x_left <= v.cursor[0] && v.cursor[0] < (x_left + x_cross) &&
            x_top <= v.cursor[1] && v.cursor[1] < (x_top + x_cross) {
            let mut kill_click = false;
            if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
               v.dead_tab = DeadTab::None;
               kill_click = true;
            } }
            if kill_click { v.clicked = None; }
         }
         
      }
      DeadTab::Load(sel, scr) => {

         let load_border = graphics::Rectangle::new_border([0.4, 0.4, 1.0, 1.0], 0.7).color([0.8, 0.8, 0.8, 0.95]);
         load_border.draw([
            char_em*1.5, char_em*1.5, v.f_width-char_em*3.0, v.f_height-char_em*3.0
         ], &c.draw_state, c.transform, g);

         let x_left = v.f_width - 2.5*char_em;
         let x_top = 1.0 * char_em;
         let x_cross = 1.5 * char_em;
         rectangle([0.4, 0.4, 1.0, 1.0],
            [x_left, x_top, x_cross, x_cross],
                  c.transform, g);

         if x_left <= v.cursor[0] && v.cursor[0] < (x_left + x_cross) &&
            x_top <= v.cursor[1] && v.cursor[1] < (x_top + x_cross) {
            let mut kill_click = false;
            if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
               v.dead_tab = DeadTab::None;
               kill_click = true;
            } }
            if kill_click { v.clicked = None; }
         }

         let transform = c.transform.trans(box_left, box_high + char_height);
         text::Text::new_color([0.2, 0.2, 1.0, 1.0], ((char_em * 1.5) as u32)).draw(
            "Souls list",
            &mut v.macondo,
            &c.draw_state,
            transform, g
         );

         let notch_high = box_high + 2.0 * char_height;

         for ci in 0..gm.class_list.len() {
            let classname = gm.class_list[ci].clone();

            let mut active = false;
            if box_left <= v.cursor[0] && v.cursor[0] < (box_left + 12.0 * char_em) &&
               (notch_high + (ci as f64) * 1.6 * char_height) <= v.cursor[1] && v.cursor[1] < (notch_high + (ci as f64) * 1.6 * char_height + 1.2*char_height) {
               active = true;
            }
            let cls_box_colour = [1.0, 1.0, 1.0, 1.0];
            rectangle(cls_box_colour,
               [box_left, notch_high + (ci as f64) * 1.6 * char_height, 12.0 * char_em, 1.2*char_height],
             c.transform, g);

            let (mut r,mut y,mut b) = gm.from_class( gm.class_list[ci].clone() );
            for clsi in 0..3 {
               let mut colour = [1.0, 1.0, 1.0, 1.0];
               if r>0 { colour = [1.0, 0.4, 0.4, 1.0]; r -= 1; }
               else if y>0 { colour = [1.0, 1.0, 0.4, 1.0]; y -= 1; }
               else if b>0 { colour = [0.4, 0.4, 1.0, 1.0]; b -= 1; }

               rectangle(colour,
               [box_left + (clsi as f64) * char_em, notch_high + (ci as f64) * 1.6 * char_height, char_em, 1.2*char_height],
                c.transform, g);
            }

            let transform = c.transform.trans(box_left + 5.0 * char_em, notch_high + (ci as f64) * 1.6 * char_height + 24.0);
            text::Text::new_color([0.1, 0.1, 0.1, 1.0], (char_em as u32)).draw(
               gm.class_list[ci].as_str(),
               &mut v.macondo,
               &c.draw_state,
               transform, g
            );
         }

         let savebase_right = v.f_width - 4.5*char_em;
         let savebase_left = box_left + 14.0*char_em;;
         for save_i in 0..5 {
         if savebase_left + ((save_i+1) as f64)*10.0*char_em < savebase_right {
            let boxleft = savebase_left + (save_i as f64)*10.0*char_em;
            for ci in 0..gm.class_list.len() {
               let classname = gm.class_list[ci].clone();
               let saves = match v.savefiles.get(&classname) {
                  Some(vs) => { vs.clone() }
                  None => { vec![] }
               };

               let boxtop = notch_high + (ci as f64) * 1.6 * char_height;
               let mut cls_box_colour = [1.0, 1.0, 1.0, 1.0];

               if boxleft <= v.cursor[0] && v.cursor[0] < (boxleft + 9.0*char_em) &&
                  boxtop <= v.cursor[1] && v.cursor[1] < (boxtop + 1.2*char_height) {
                  cls_box_colour = [1.0, 1.0, 0.7, 1.0];

                  let mut kill_click = false;
                  let mut savefile = None;
                  if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
                     if save_i < saves.len() {
                        let (csteps, ref cname, ref cpath) = saves[save_i];
                        savefile = Some(cpath);
                     }
                     kill_click = true;
                  } }
                  if kill_click { v.clicked = None; }
                  if savefile.is_some() { v.load_savefile(gm, savefile.unwrap().clone()) };

               }

               rectangle(cls_box_colour,
                  [boxleft, boxtop, 9.0 * char_em, 1.2*char_height],
                   c.transform, g);

               let mut text_colour = [0.7, 0.7, 0.7, 1.0];
               let mut text_content = "[Empty Save]".to_string();
               if save_i < saves.len() {
                  let (csteps, cname, cpath) = saves[save_i].clone();
                  text_colour = [0.2, 0.2, 0.2, 1.0];
                  text_content = cname;
               }

               let transform = c.transform.trans(boxleft + 1.0 * char_em, boxtop + 24.0);
               text::Text::new_color(text_colour, (char_em as u32)).draw(
                  text_content.as_str(),
                  &mut v.macondo,
                  &c.draw_state,
                  transform, g
               );

            }
         }}
      }
   }
}

pub fn render_partitions(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   rectangle([1.0, 1.0, 1.0, 1.0],
             [0.0, 0.0, v.f_width, 3.0*v.f_em],
             c.transform, g);
   rectangle([0.8, 0.2, 0.2, 1.0],
             [0.0, 3.0*v.f_em, v.f_width, 0.5*v.f_em],
             c.transform, g);
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   rectangle([0.8, 0.2, 0.2, 1.0],
             [mid_left, 3.0*v.f_em, 0.5*v.f_em, v.f_height],
             c.transform, g);
}

pub fn render_agent_resources(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let char_high = 5.5 * v.f_em;
   let char_left = mid_left + 2.0 * v.f_em;
   let char_width = mid_left - 4.0 * v.f_em;
   let char_height = 28.0;
   let char_height_lift = 20.0;
   let char_em = 13.0;
   let img_width = 256.0;

   let aspect = img_width / 512.0;
   let mut texture_name = "avatar_".to_string();
   texture_name.push_str( gm.agent_class.as_str() );
   texture_name.push_str( ".png" );
   let agent_texture = v.texture(texture_name);
   let t = c.transform
            .trans(char_left, char_high)
            .scale(aspect, aspect);
   image(&agent_texture, t, g);

   let agent_stats = gm.agent_stats();
   //health
   let agent_health_border = graphics::Rectangle::new_border([1.0, 0.4, 0.4, 1.0], 1.0).color([0.8, 0.8, 0.8, 1.0]);
   agent_health_border.draw([
      char_left, char_high+img_width+char_em, img_width, char_height
   ], &c.draw_state, c.transform, g);
   let agent_health_cur = agent_stats.cur_health;
   let agent_health_max = agent_stats.max_health;
   let agent_health_pixels = ((img_width - 2.0) * (agent_health_cur as f64)) / (agent_health_max as f64);
   rectangle([1.0, 0.4, 0.4, 1.0],
             [char_left+1.0, char_high+img_width+char_em, agent_health_pixels, char_height],
             c.transform, g);
   let agent_health_text = format!("{} / {}", agent_health_cur, agent_health_max);
   let transform = c.transform.trans(char_left+char_em, char_high+img_width+char_em+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], char_em as u32).draw(
      agent_health_text.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );
   //energy
   let agent_energy_border = graphics::Rectangle::new_border([1.0, 1.0, 0.4, 1.0], 1.0).color([0.8, 0.8, 0.8, 1.0]);
   agent_energy_border.draw([
      char_left, char_high+img_width+2.0*char_em+char_height, img_width, char_height
   ], &c.draw_state, c.transform, g);
   let agent_energy_cur = agent_stats.cur_energy;
   let agent_energy_max = agent_stats.max_energy;
   let agent_energy_pixels = ((img_width - 2.0) * (agent_energy_cur as f64)) / (agent_energy_max as f64);
   rectangle([1.0, 1.0, 0.4, 1.0],
             [char_left+1.0, char_high+img_width+2.0*char_em+char_height, agent_energy_pixels, char_height],
             c.transform, g);
   let agent_energy_text = format!("{} / {}", agent_energy_cur, agent_energy_max);
   let transform = c.transform.trans(char_left+char_em, char_high+img_width+2.0*char_em+char_height+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], char_em as u32).draw(
      agent_energy_text.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );
   //mana
   let agent_mana_border = graphics::Rectangle::new_border([0.4, 0.4, 1.0, 1.0], 1.0).color([0.8, 0.8, 0.8, 1.0]);
   agent_mana_border.draw([
      char_left, char_high+img_width+3.0*char_em+2.0*char_height, img_width, char_height
   ], &c.draw_state, c.transform, g);
   let agent_mana_cur = agent_stats.cur_mana;
   let agent_mana_max = agent_stats.max_mana;
   let agent_mana_pixels = ((img_width - 2.0) * (agent_mana_cur as f64)) / (agent_mana_max as f64);
   rectangle([0.4, 0.4, 1.0, 1.0],
             [char_left+1.0, char_high+img_width+3.0*char_em+2.0*char_height, agent_mana_pixels, char_height],
             c.transform, g);
   let agent_mana_text = format!("{} / {}", agent_mana_cur, agent_mana_max);
   let transform = c.transform.trans(char_left+char_em, char_high+img_width+3.0*char_em+2.0*char_height+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], char_em as u32).draw(
      agent_mana_text.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   let agent_name = format!("{}", gm.agent_name.clone());
   let transform = c.transform.trans(char_left, char_high+img_width+4.0*char_em+3.5*char_height+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], (1.4*char_em) as u32).draw(
      agent_name.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   let norm_agent_stats = agent_stats.normalize();
   let (cls, lvl) = gm.to_classlvl(&norm_agent_stats);
   let cls = gm.agent_class.clone();
   let agent_classlvl = format!("Level {} {}", lvl, cls);
   let transform = c.transform.trans(char_left, char_high+img_width+4.0*char_em+5.0*char_height+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], (1.4*char_em) as u32).draw(
      agent_classlvl.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

}

pub fn render_nav(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let em = 16.5;
   let items = [
      "Map",
      "Character",
      "Inventory",
      "Library",
      "Quests",
      "Save"
   ];
   let mut offset_x = 2.0 * em;
   for i in 0.. items.len() {
      let word = items[i];
      let offset_y = 2.0 * v.f_em;
      let word_height = v.f_em;
      let word_width = (word.len() as f64) * em;

      let word_colour = if word.to_string() == v.tab {
         [
            [0.8, 0.2, 0.2, 1.0],
            [0.866, 0.4, 0.4, 1.0],
            [0.933, 0.6, 0.6, 1.0],
            [1.0, 0.8, 0.8, 1.0]
         ]
      } else {
         [
            [0.2, 0.2, 0.2, 1.0],
            [0.4, 0.4, 0.4, 1.0],
            [0.6, 0.6, 0.6, 1.0],
            [0.8, 0.8, 0.8, 1.0]
         ]
      };

      let box_x = (offset_x) - 10.0;
      let box_y = (offset_y - v.f_em + 3.0) - 10.0;
      let box_width = word_width + 20.0;
      let box_height = word_height + 20.0;

      if box_x <= v.cursor[0] && v.cursor[0] <= (box_x+box_width) &&
         box_y <= v.cursor[1] && v.cursor[1] <= (box_y+box_height) {

         let mut kill_click = false;
         if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
            if word.to_string() == "Save" {
               v.tab = "Map".to_string();
               gm.save();
               gm.say("You feel time passing more slowly.".to_string());
               kill_click = true;
            } else {
               v.tab = word.to_string();
               v.item_has_focus = -1;
            }
         } }
         if kill_click { v.clicked = None; }

         let transform = c.transform.trans(offset_x-3.0, offset_y+3.0);
         text::Text::new_color(word_colour[3], v.i_em).draw(
            word,
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
         let transform = c.transform.trans(offset_x-2.0, offset_y+2.0);
         text::Text::new_color(word_colour[2], v.i_em).draw(
            word,
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
         let transform = c.transform.trans(offset_x-1.0, offset_y+1.0);
         text::Text::new_color(word_colour[1], v.i_em).draw(
            word,
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );

      }

      let transform = c.transform.trans(offset_x, offset_y);
      text::Text::new_color(word_colour[0], v.i_em).draw(
         word,
         &mut v.monofont,
         &c.draw_state,
         transform, g
      );
      offset_x += word_width + 2.0 * em;
   }

}

pub fn render_fight(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let char_high = 5.5 * v.f_em;
   let char_left = mid_left + 2.0 * v.f_em;
   let char_width = mid_left - 4.0 * v.f_em;
   let char_height = 28.0;
   let char_height_lift = 20.0;
   let char_em = 13.0;
   let img_width = 256.0;
   
   render_agent_resources(gm, v, c, g);

   let aspect = img_width / 512.0;
   let (enemy_texture, enemy_name, enemy_stats) = match gm.agent_engaged.clone() {
      Some((x,y,ws)) => {
         let stats = gm.enemy_stats(&ws).clone();
         let ww = ws[0].clone();
         match ww {
            Word::Audio(s) => {
               let mut t = "avatar_".to_string();
               t.push_str(s.as_str());
               t.push_str(".png");
               (t, s.clone(), stats)
            }
            _ => { panic!("creature first slot should hold an Audio word"); }
         }
      }
      _ => { ("unknown.png".to_string(), "?".to_string(), gm.enemy_stats(&vec![]).clone()) }
   };
   let enemy_texture = v.texture(enemy_texture);
   let t = c.transform
            .trans(char_left + char_width - img_width, char_high)
            .scale(aspect, aspect);
   image(&enemy_texture, t, g);

   
   let enemy_left = char_left+char_width-img_width;
   //health
   let enemy_health_border = graphics::Rectangle::new_border([1.0, 0.4, 0.4, 1.0], 1.0).color([0.8, 0.8, 0.8, 1.0]);
   enemy_health_border.draw([
      enemy_left, char_high+img_width+char_em, img_width, char_height
   ], &c.draw_state, c.transform, g);
   let enemy_health_cur = enemy_stats.cur_health;
   let enemy_health_max = enemy_stats.max_health;
   let enemy_health_pixels = ((img_width - 2.0) * (enemy_health_cur as f64)) / (enemy_health_max as f64);
   rectangle([1.0, 0.4, 0.4, 1.0],
             [enemy_left+1.0, char_high+img_width+char_em, enemy_health_pixels, char_height],
             c.transform, g);
   let enemy_health_text = format!("{} / {}", enemy_health_cur, enemy_health_max);
   let transform = c.transform.trans(enemy_left+char_em, char_high+img_width+char_em+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], char_em as u32).draw(
      enemy_health_text.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );
   //energy
   let enemy_energy_border = graphics::Rectangle::new_border([1.0, 1.0, 0.4, 1.0], 1.0).color([0.8, 0.8, 0.8, 1.0]);
   enemy_energy_border.draw([
      enemy_left, char_high+img_width+2.0*char_em+char_height, img_width, char_height
   ], &c.draw_state, c.transform, g);
   let enemy_energy_cur = enemy_stats.cur_energy;
   let enemy_energy_max = enemy_stats.max_energy;
   let enemy_energy_pixels = ((img_width - 2.0) * (enemy_energy_cur as f64)) / (enemy_energy_max as f64);
   rectangle([1.0, 1.0, 0.4, 1.0],
             [enemy_left+1.0, char_high+img_width+2.0*char_em+char_height, enemy_energy_pixels, char_height],
             c.transform, g);
   let enemy_energy_text = format!("{} / {}", enemy_energy_cur, enemy_energy_max);
   let transform = c.transform.trans(enemy_left+char_em, char_high+img_width+2.0*char_em+char_height+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], char_em as u32).draw(
      enemy_energy_text.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );
   //mana
   let enemy_mana_border = graphics::Rectangle::new_border([0.4, 0.4, 1.0, 1.0], 1.0).color([0.8, 0.8, 0.8, 1.0]);
   enemy_mana_border.draw([
      enemy_left, char_high+img_width+3.0*char_em+2.0*char_height, img_width, char_height
   ], &c.draw_state, c.transform, g);
   let enemy_mana_cur = enemy_stats.cur_mana;
   let enemy_mana_max = enemy_stats.max_mana;
   let enemy_mana_pixels = ((img_width - 2.0) * (enemy_mana_cur as f64)) / (enemy_mana_max as f64);
   rectangle([0.4, 0.4, 1.0, 1.0],
             [enemy_left+1.0, char_high+img_width+3.0*char_em+2.0*char_height, enemy_mana_pixels, char_height],
             c.transform, g);
   let enemy_mana_text = format!("{} / {}", enemy_mana_cur, enemy_mana_max);
   let transform = c.transform.trans(enemy_left+char_em, char_high+img_width+3.0*char_em+2.0*char_height+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], char_em as u32).draw(
      enemy_mana_text.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   //class level
   let norm_enemy_stats = enemy_stats.normalize();
   let (cls, lvl) = gm.to_classlvl(&norm_enemy_stats);
   let enemy_classlvl = format!("Level {} {}", lvl, enemy_name);
   let transform = c.transform.trans(enemy_left, char_high+img_width+4.0*char_em+3.5*char_height+char_height_lift);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], (1.4*char_em) as u32).draw(
      enemy_classlvl.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );
}

pub fn render_chat(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let chat_high = 5.5 * v.f_em;
   let chat_left = mid_left + 2.0 * v.f_em;
   let chat_width = mid_left - 4.0 * v.f_em;
   let chat_height = 36.0;
   let chat_em = 30.0;
   let mut chat_colour = [1.0, 1.0, 1.0, 1.0];
   let mut chat_border_colour = [0.625, 0.625, 0.625, 1.0];

   if let Some(_) = v.clicked {
      if chat_left <= v.cursor[0] && v.cursor[0] <= (chat_left+chat_width) &&
         chat_high <= v.cursor[1] && v.cursor[1] <= (chat_high+chat_height) {
         v.search_has_focus = true;
      } else {
         v.search_has_focus = false;
      }
   }

   if v.search_has_focus {
      let mut brightness_factor = gm.circuit(3.0);
      if brightness_factor < 1.0 {
         brightness_factor = (1.0 - brightness_factor) / 1.0;
         brightness_factor = brightness_factor * 0.9 + 0.1;
      } else {
         brightness_factor -= 1.0;
         brightness_factor = brightness_factor / 2.0;
         brightness_factor = brightness_factor * 0.9 + 0.1;
      }
      let bf = brightness_factor as f32;
      chat_border_colour = [0.9*bf, 0.4*bf, 0.4*bf, 1.0];
   }

   if gm.chat_log.len() > 100 { gm.chat_log.remove(0); }

   let search_border = graphics::Rectangle::new_border(chat_border_colour, 1.0).color(chat_colour);
   search_border.draw([ 
      chat_left, chat_high, chat_width, chat_height
   ], &c.draw_state, c.transform, g);

   let transform = c.transform.trans(chat_left + 12.0, chat_high+29.0);
   text::Text::new_color(chat_border_colour, 24.0 as u32).draw(
      gm.chat_bar.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   rectangle(chat_border_colour, [
      chat_left + 18.0 + (gm.chat_bar.len() as f64) * 16.0,
      chat_high + 3.0, 2.0, chat_height - 6.0
   ], c.transform, g);

   for i in 0.. gm.chat_log.len() {
      let row_size = 38.0;
      let row_text = 24.0;
      let x = chat_left;
      let y = chat_high + 70.0 + (i as f64)*row_size;
      let aspect = row_text / 512.0;
      let t = c.transform
               .trans(x, y)
               .scale(aspect, aspect);
      let ref ch = gm.chat_log[gm.chat_log.len() - 1 - i];
      
      let speaker = match &ch.source {
         &Word::Audio(ref s) => { s.clone() }
         _ => { "".to_string() }
      };
      let sigil = v.texture(speaker);
      image(&sigil, t, g);

      let sen = if ch.content.len()==0 { "".to_string() }
      else {match &ch.content[0] {
         &Word::Audio(ref w) => { w.clone() }
         _ => { "".to_string() }
      }};
      let transform = c.transform.trans(x + 32.0, y + 19.0);
      text::Text::new_color([0.9*0.2, 0.4*0.2, 0.4*0.2, 1.0], 24.0 as u32).draw(
         sen.as_str(),
         &mut v.monofont,
         &c.draw_state,
         transform, g
      );

   }
}

pub fn render_agent_equipment(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let eq_height = 28.0;
   let eq_high = 5.5 * v.f_em + 2.0 * eq_height;
   let eq_width = mid_left - 4.0 * v.f_em;
   let eq_em = 16.0;
   let eq_left = mid_left + 2.0 * v.f_em + eq_width / 2.0 + 3.0 * eq_em;
   let eq_height_lift = 24.0;

   let transform = c.transform.trans(eq_left, eq_high);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], (2.0 * eq_em) as u32).draw(
     "Equipped",
     &mut v.monofont,
     &c.draw_state,
     transform, g
   );

   let mut ni = 2.0;
   for ii in 0..gm.agent_equipped.len() {
      ni += 1.0;
      let e = gm.agent_equipped[ii].clone();
      let eq = gm.display_equipment(&e);
      let ieq_high = eq_high + (1.0 + (ii as f64)) * eq_height;

      if eq_left <= v.cursor[0] && v.cursor[0] < (eq_left + 30.0 * eq_em) &&
         ieq_high <= v.cursor[1] && v.cursor[1] < (ieq_high + eq_height) {
         for ix in -2..3 {
         for iy in -2..3 {
            let transform = c.transform.trans(eq_left - (ix as f64), ieq_high + eq_height + (iy as f64));
            text::Text::new_color([1.0, 0.4, 0.4, 1.0], eq_em as u32).draw(
               eq.as_str(),
               &mut v.monofont,
               &c.draw_state,
               transform, g
            );
         }}

         let mut kill_click = false;
         if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
            v.equip_has_focus = ii as i32;
            kill_click = true;
         }}
         if kill_click { v.clicked = None; }
      }
      let transform = c.transform.trans(eq_left, ieq_high + eq_height);
      text::Text::new_color([0.0, 0.0, 0.0, 1.0], eq_em as u32).draw(
        eq.as_str(),
        &mut v.monofont,
        &c.draw_state,
        transform, g
      );
   }

   let stat_high = eq_high + ni * eq_height;
   rectangle([0.0, 0.0, 0.0, 1.0],
             [eq_left, stat_high, (mid_left + eq_width) - eq_left, 3.0],
             c.transform, g);

   let stats = gm.agent_stats();
   for ei in 0..10 {
      let text = if ei==0 {
         format!("strength: {}", stats.strength)
      } else if ei==1 {
         format!("agility: {}", stats.agility)
      } else if ei==2 {
         format!("intelligence: {}", stats.intelligence)
      } else if ei==3 {
         format!("force: {}", stats.force)
      } else if ei==4 {
         format!("accuracy: {}", stats.accuracy)
      } else if ei==5 {
         format!("enhancement: {}", stats.enhancement)
      } else if ei==6 {
         format!("protect: {}", stats.protect)
      } else if ei==7 {
         format!("deflect: {}", stats.deflect)
      } else if ei==8 {
         format!("absorb: {}", stats.absorb)
      } else if ei==9 {
         format!("speed: {}", stats.speed)
      } else { panic!("Dead code"); };

      let transform = c.transform.trans(eq_left, stat_high + 13.0 + ((ei+1) as f64) * eq_height);
      text::Text::new_color([0.0, 0.0, 0.0, 1.0], eq_em as u32).draw(
        text.as_str(),
        &mut v.monofont,
        &c.draw_state,
        transform, g
      );
   }
}

pub fn render_character(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   //left panel
   if v.equip_has_focus >= 0 {
      render_equip_focus(gm, v, c, g);
   } else {
      render_map(gm, v, c, g);
   }
   //right panel
   if gm.agent_engaged.is_some() {
      render_fight(gm, v, c, g);
   } else {
      render_agent_resources(gm, v, c, g);
      render_agent_equipment(gm, v, c, g);
   }
}
pub fn render_equip_focus(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {

   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let inv_high = 5.5 * v.f_em;
   let inv_left = 2.0 * v.f_em;
   let inv_width = mid_left - 4.0 * v.f_em;
   let inv_height = 28.0;
   let inv_height_lift = 24.0;
   let inv_em = 13.0;
   let img_width = 256.0;
   let bold_em = 1.5 * inv_em;
   let bold_height = 1.5 * inv_height;

   //BEGIN LEFT FOLD
   let itm = gm.agent_equipped[ v.equip_has_focus as usize ].clone();
   let itm_name = match &itm[0] {
      &Word::Audio(ref w) => { w.clone() }
      _ => { "???".to_string() }
   };
   let mut texture_name = "item_".to_string();
   texture_name.push_str( itm_name.as_str() );
   texture_name.push_str( ".png" );
   
   let sigil = v.texture(texture_name);
   let aspect = img_width / 512.0;
   let t = c.transform
            .trans(inv_left, inv_high)
            .scale(aspect, aspect);
   image(&sigil, t, g);
   //END LEFT FOLD

   //BEGIN TOP RIGHT FOLD
   let bold_left = inv_left + img_width + 2.0 * inv_em;
   let transform = c.transform.trans(bold_left, inv_high + bold_em);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], bold_em as u32).draw(
         itm_name.as_str(),
         &mut v.monofont,
         &c.draw_state,
         transform, g
   );

   let float_left = inv_left + img_width + 1.0 * inv_em;
   let float_high = inv_high + 3.0 * bold_em;
   let rarity = gm.item_rarity(itm_name.clone());
   match rarity {
      None => {
         let transform = c.transform.trans(float_left, float_high);
         text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
            "This item cannot be found here",
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }
      Some(r) => {
         let s = format!("Rarity: 1/{} items", (r as u64));
         let transform = c.transform.trans(float_left, float_high);
         text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
            s.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }
   }

   let stats = gm.item_description(itm_name.clone());

   let i_type = if let Some("equip") = stats["type"].as_str() { "equip" }
   else if let Some("consumable") = stats["type"].as_str() { "consumable" }
   else if let Some("knowledge") = stats["type"].as_str() { "knowledge" }
   else { panic!("type must be red, yellow or blue") };
   let s = format!("type: {}", i_type);
   let transform = c.transform.trans(float_left, float_high + 1.0*inv_height);
   text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
      s.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   let (modifier, value) = if i_type == "equip" {
      ("slot", stats["slot"].as_str())
   } else if i_type == "consumable" {
      ("regent", stats["regent"].as_str())
   } else if i_type == "knowledge" {
      ("family", stats["family"].as_str())
   } else { panic!("dead code"); };
   let value = match value {
      Some(s) => { s }
      None => { panic!("No class specified for item: {}", itm_name.clone()) }
   };
   let s = format!("{}: {}", modifier, value);
   let transform = c.transform.trans(float_left, float_high + 2.0*inv_height);
   text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
      s.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   let affinity = if let Some(s) = stats["affinity"].as_str() { s.clone() }
   else { "neutral" };
   let s = format!("affinity: {}", affinity);
   let transform = c.transform.trans(float_left, float_high + 3.0*inv_height);
   text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
      s.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   let plusminus = gm.item_stats(itm);
   for pmi in 0..6 {
      let (stat, diff) = if pmi==0 { ("force", plusminus.force) }
      else if pmi==1 { ("accuracy", plusminus.accuracy) }
      else if pmi==2 { ("enhancement", plusminus.enhancement) }
      else if pmi==3 { ("protect", plusminus.protect) }
      else if pmi==4 { ("deflect", plusminus.deflect) }
      else if pmi==5 { ("absorb", plusminus.absorb) }
      else { panic!("dead code"); };

      let s = format!("{}: {}", stat, diff);
      let colour = [0.2, 0.2, 0.2, 1.0];
      let transform = c.transform.trans(float_left, float_high + (4.0 + (pmi as f64))*inv_height);
      text::Text::new_color(colour, inv_em as u32).draw(
         s.as_str(),
         &mut v.monofont,
         &c.draw_state,
         transform, g
      );
   }

   //Right-top equip stats
      //elemental affinity
      //modifiers, uniques, and scalings
      //rarity colour
   //END TOP RIGHT FOLD

   //BEGIN BOTTOM RIGHT FOLD (currently equipped)
   //Equip
   //--- fold ---
   //category
   //appears in
   //description

}
pub fn render_inventory(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let inv_high = 5.5 * v.f_em;
   let inv_left = mid_left + 2.0 * v.f_em;
   let inv_width = mid_left - 4.0 * v.f_em;
   let inv_height = 28.0;
   let inv_height_lift = 24.0;
   let inv_em = 16.0;

   for ii in 0.. (gm.agent_inventory.len()+1) {

      let x = inv_left;
      let y = inv_high + 70.0 + (ii as f64)*inv_height;

      if let Some(_) = v.clicked {
         if x <= v.cursor[0] && v.cursor[0] <= (x+inv_width) &&
            y <= v.cursor[1] && v.cursor[1] < (y+inv_height) &&
            ii < gm.agent_inventory.len() {
         v.item_has_focus = ii as i32;
      } }

      if (ii as i32) == v.item_has_focus {
         let colour = [0.6, 0.6, 1.0, 1.0];
         rectangle(colour,
                [inv_left, y, inv_width, inv_height],
                c.transform, g);
      } else if x <= v.cursor[0] && v.cursor[0] <= (x+inv_width) &&
         y <= v.cursor[1] && v.cursor[1] < (y+inv_height) {
         let colour = [1.0, 0.6, 0.6, 1.0];
         rectangle(colour,
                [inv_left, y, inv_width, inv_height],
                c.transform, g);
      }

      let (itm, qty) = if ii<gm.agent_inventory.len() {
         let (itm, qty) = gm.agent_inventory[ii].clone();
         let name = gm.display_equipment(&itm);
         (name, qty)
      } else { ("...".to_string(), 0) };

      if ii < gm.agent_inventory.len() {
         let transform = c.transform.trans(x, y+inv_height_lift);
         let count = format!("{:05} x", qty);
         text::Text::new_color([0.0, 0.0, 0.0, 1.0], inv_em as u32).draw(
            count.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }

      let transform = c.transform.trans(x + 7.0 * inv_em, y+inv_height_lift);
      text::Text::new_color([0.9*0.2, 0.4*0.2, 0.4*0.2, 1.0], inv_em as u32).draw(
         itm.replace("_"," ").as_str(),
         &mut v.monofont,
         &c.draw_state,
         transform, g
      );
   }
   if v.item_has_focus < 0 {
      render_map(gm, v, c, g);
   } else {
      render_item_focus(gm, v, c, g);
   }
}
pub fn render_item_focus(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let inv_high = 5.5 * v.f_em;
   let inv_left = 2.0 * v.f_em;
   let inv_width = mid_left - 4.0 * v.f_em;
   let inv_height = 28.0;
   let inv_height_lift = 24.0;
   let inv_em = 13.0;
   let img_width = 256.0;
   let bold_em = 1.5 * inv_em;
   let bold_height = 1.5 * inv_height;

   //BEGIN LEFT FOLD   
   let (itm,qty) = gm.agent_inventory[ v.item_has_focus as usize ].clone();
   let itm_name = match &itm[0] {
      &Word::Audio(ref w) => { w.clone() }
      _ => { "???".to_string() }
   };
   let mut texture_name = "item_".to_string();
   texture_name.push_str( itm_name.as_str() );
   texture_name.push_str( ".png" );
   
   let sigil = v.texture(texture_name);
   let aspect = img_width / 512.0;
   let t = c.transform
            .trans(inv_left, inv_high)
            .scale(aspect, aspect);
   image(&sigil, t, g);

   let item_type = gm.item_type(&itm);
   if item_type == "equip".to_string() {
      let item_slot = gm.item_slot(&itm);
      let a = gm.agent_stats();
      let prereq = gm.stats_requirements(v.item_has_focus);
      let mut pass = a.strength >= prereq.strength && a.agility >= prereq.agility && a.intelligence >= prereq.intelligence;

      let equip_high = inv_high + img_width + inv_height + inv_height_lift;
      if item_slot == "miscellaneous".to_string() {
      } else if !pass {
      } else if inv_left <= v.cursor[0] && v.cursor[0] < (inv_left + img_width - 2.0 * bold_em) &&
         (equip_high - bold_height - 3.0) <= v.cursor[1] && v.cursor[1] < (equip_high + 3.0) {
         for oxi in -2..3 {
         for oyi in -2..3 {
            let transform = c.transform.trans(inv_left + bold_em + (oxi as f64), inv_high + img_width + inv_height + inv_height_lift + (oyi as f64));
            text::Text::new_color([0.0, 0.0, 0.0, 1.0], bold_em as u32).draw(
               "Equip Now",
               &mut v.monofont,
               &c.draw_state,
            transform, g
            );
         }}
         let transform = c.transform.trans(inv_left + bold_em, inv_high + img_width + inv_height + inv_height_lift);
         text::Text::new_color([1.0, 0.4, 0.4, 1.0], bold_em as u32).draw(
            "Equip Now",
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );

         let mut kill_click = false;
         if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
            if v.item_has_focus >= 0 {
               gm.equip(v.item_has_focus);
            }
            v.item_has_focus = -1;
         }}
         if kill_click { v.clicked = None; }
      } else {
         let transform = c.transform.trans(inv_left + bold_em + 1.0, inv_high + img_width + inv_height + inv_height_lift+ 1.0);
         text::Text::new_color([0.0, 0.0, 0.0, 1.0], bold_em as u32).draw(
            "Equip Now",
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
         let transform = c.transform.trans(inv_left + bold_em, inv_high + img_width + inv_height + inv_height_lift);
         text::Text::new_color([1.0, 0.4, 0.4, 1.0], bold_em as u32).draw(
            "Equip Now",
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }
   } else if item_type == "consumable".to_string() {

      let consume_high = inv_high + img_width + inv_height + inv_height_lift;
      let verb = gm.item_verb(&itm);
      let verb_now = format!("{} Now", verb);

      if inv_left <= v.cursor[0] && v.cursor[0] < (inv_left + img_width - 2.0 * bold_em) &&
         (consume_high - bold_height - 3.0) <= v.cursor[1] && v.cursor[1] < (consume_high + 3.0) {
         for oxi in -2..3 {
         for oyi in -2..3 {
            let transform = c.transform.trans(inv_left + bold_em + (oxi as f64), inv_high + img_width + inv_height + inv_height_lift + (oyi as f64));
            text::Text::new_color([0.0, 0.0, 0.0, 1.0], bold_em as u32).draw(
               verb_now.as_str(),
               &mut v.monofont,
               &c.draw_state,
            transform, g
            );
         }}
         let transform = c.transform.trans(inv_left + bold_em, inv_high + img_width + inv_height + inv_height_lift);
         text::Text::new_color([1.0, 0.4, 0.4, 1.0], bold_em as u32).draw(
            verb_now.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );

         let mut kill_click = false;
         if let Some(ref btn) = v.clicked { if btn.to_string()=="Left" {
            gm.item_do_use(&itm);
            v.item_has_focus = -1;
         }}
         if kill_click { v.clicked = None; }
      } else {
         let transform = c.transform.trans(inv_left + bold_em + 1.0, inv_high + img_width + inv_height + inv_height_lift+ 1.0);
         text::Text::new_color([0.0, 0.0, 0.0, 1.0], bold_em as u32).draw(
            verb_now.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
         let transform = c.transform.trans(inv_left + bold_em, inv_high + img_width + inv_height + inv_height_lift);
         text::Text::new_color([1.0, 0.4, 0.4, 1.0], bold_em as u32).draw(
            verb_now.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }
   } else if item_type == "knowledge".to_string() {
      println!("TODO: knowledge inspect");
   } else {
      panic!("Could not determine item type: {:?}", itm);
   }
   //END LEFT FOLD

   //BEGIN TOP RIGHT FOLD
   let item_pretty_name = gm.display_equipment(&itm);
   let bold_left = inv_left + img_width + 2.0 * inv_em;
   let transform = c.transform.trans(bold_left, inv_high + bold_em);
   text::Text::new_color([0.0, 0.0, 0.0, 1.0], bold_em as u32).draw(
         item_pretty_name.as_str(),
         &mut v.monofont,
         &c.draw_state,
         transform, g
   );

   let float_left = inv_left + img_width + 1.0 * inv_em;
   let float_high = inv_high + 3.0 * bold_em;
   let rarity = gm.item_rarity(itm_name.clone());
   match rarity {
      None => {
         let transform = c.transform.trans(float_left, float_high);
         text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
            "This item cannot be found here",
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }
      Some(r) => {
         let s = format!("Rarity: 1/{} items", (r as u64));
         let transform = c.transform.trans(float_left, float_high);
         text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
            s.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }
   }

   let stats = gm.item_description(itm_name.clone());

   let i_type = if let Some("equip") = stats["type"].as_str() { "equip" }
   else if let Some("consumable") = stats["type"].as_str() { "consumable" }
   else if let Some("knowledge") = stats["type"].as_str() { "knowledge" }
   else { panic!("type must be red, yellow or blue") };
   let s = format!("type: {}", i_type);
   let transform = c.transform.trans(float_left, float_high + 1.0*inv_height);
   text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
      s.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   let (modifier, value) = if i_type == "equip" {
      ("slot", stats["slot"].as_str())
   } else if i_type == "consumable" {
      ("regent", stats["regent"].as_str())
   } else if i_type == "knowledge" {
      ("family", stats["family"].as_str())
   } else { panic!("dead code"); };
   let value = match value {
      Some(s) => { s }
      None => { panic!("No class specified for item: {}", itm_name.clone()) }
   };
   let s = format!("{}: {}", modifier, value);
   let transform = c.transform.trans(float_left, float_high + 2.0*inv_height);
   text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
      s.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   let affinity = if let Some(s) = stats["affinity"].as_str() { s.clone() }
   else { "neutral" };
   let s = format!("affinity: {}", affinity);
   let transform = c.transform.trans(float_left, float_high + 3.0*inv_height);
   text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
      s.as_str(),
      &mut v.monofont,
      &c.draw_state,
      transform, g
   );

   if v.item_has_focus < 0 {
      //pass
   } else if item_type == "equip".to_string() {
      let prereq = gm.stats_requirements(v.item_has_focus);
      for pmi in 0..3 {
         let a = gm.agent_stats();
         let (stat, val, cur) = if pmi==0 { ("strength", prereq.strength, a.strength) }
         else if pmi==1 { ("agility", prereq.agility, a.agility) }
         else if pmi==2 { ("intelligence", prereq.intelligence, a.intelligence) }
         else { panic!("dead code"); };
         let s = format!("requires {} {} ({})", val, stat, cur);
         let colour = if cur>val { [0.0, 0.6, 0.0, 1.0] }
                 else if cur<val { [1.0, 0.4, 0.4, 1.0] }
                 else            { [0.2, 0.2, 0.2, 1.0] };
         let transform = c.transform.trans(float_left, float_high + (4.0 + (pmi as f64))*inv_height);
         text::Text::new_color(colour, inv_em as u32).draw(
            s.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }

      let plusminus = gm.compare_equipped(v.item_has_focus);
      for pmi in 0..6 {
         let (stat, diff) = if pmi==0 { ("force", plusminus.force) }
         else if pmi==1 { ("accuracy", plusminus.accuracy) }
         else if pmi==2 { ("enhancement", plusminus.enhancement) }
         else if pmi==3 { ("protect", plusminus.protect) }
         else if pmi==4 { ("deflect", plusminus.deflect) }
         else if pmi==5 { ("absorb", plusminus.absorb) }
         else { panic!("dead code"); };

         let s = format!("{}: {}", stat, diff);
         let colour = if diff>0 { [0.0, 0.6, 0.0, 1.0] }
                 else if diff<0 { [1.0, 0.4, 0.4, 1.0] }
                 else           { [0.2, 0.2, 0.2, 1.0] };
         let transform = c.transform.trans(float_left, float_high + (7.0 + (pmi as f64))*inv_height);
         text::Text::new_color(colour, inv_em as u32).draw(
            s.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }
   } else if item_type == "consumable".to_string() {

      let on_use = gm.item_use(&itm);
      for ui in 0..on_use.len() {
         let (key, val) = on_use[ui].clone();
         let text = if key == "death".to_string() {
            format!("use: instant death")
         } else if key == "health".to_string() {
            format!("use: recover {} health", val)
         } else if key == "energy".to_string() {
            format!("use: recover {} energy", val)
         } else if key == "mana".to_string() {
            format!("use: recover {} mana", val)
         } else {
            format!("use: {} x {}", key, val)
         };

         let transform = c.transform.trans(float_left, float_high + (4.0 + (ui as f64))*inv_height);
         text::Text::new_color([0.2, 0.2, 0.2, 1.0], inv_em as u32).draw(
            text.as_str(),
            &mut v.monofont,
            &c.draw_state,
            transform, g
         );
      }

   } else if item_type == "knowledge".to_string() {
     println!("TODO knowledge 2");
   }

   //Right-top equip stats
      //elemental affinity
      //modifiers, uniques, and scalings
      //rarity colour
   //END TOP RIGHT FOLD

   //BEGIN BOTTOM RIGHT FOLD (currently equipped)
   //Equip
   //--- fold ---
   //category
   //appears in
   //description
}
pub fn render_library(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   if v.spell_has_focus == "".to_string() {
      render_map(gm, v, c, g);
   } else {
      //render_spell_focus(gm, v, c, g);
   }
   render_library_rhs(gm, v, c, g);
}
pub fn render_library_rhs(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
   let inv_high = 5.5 * v.f_em;
   let inv_left = mid_left + 2.0 * v.f_em;
   let inv_width = mid_left - 4.0 * v.f_em;
   let inv_height = 28.0;
   let inv_height_lift = 24.0;
   let inv_em = 16.0;

   gm.agent_library.insert("".to_string(), Vec::new());

   let mut ii = 0;
   for (spellname, spell) in &gm.agent_library {
      
      let x = inv_left;
      let y = inv_high + 70.0 + (ii as f64)*inv_height;

      if let Some(_) = v.clicked {
         if x <= v.cursor[0] && v.cursor[0] <= (x+inv_width) &&
            y <= v.cursor[1] && v.cursor[1] < (y+inv_height) &&
            ii < gm.agent_inventory.len() {
         v.spell_has_focus = spellname.clone();
      } }

      if *spellname == v.spell_has_focus && v.spell_has_focus != "".to_string() {
         let colour = [0.6, 0.6, 1.0, 1.0];
         rectangle(colour,
                [inv_left, y, inv_width, inv_height],
                c.transform, g);
      } else if x <= v.cursor[0] && v.cursor[0] <= (x+inv_width) &&
         y <= v.cursor[1] && v.cursor[1] < (y+inv_height) {
         let colour = [1.0, 0.6, 0.6, 1.0];
         rectangle(colour,
                [inv_left, y, inv_width, inv_height],
                c.transform, g);
      }

      let name = if spellname=="" { "...".to_string() } else { spellname.clone() };

      let transform = c.transform.trans(x, y+inv_height_lift);
      text::Text::new_color([0.0, 0.0, 0.0, 1.0], inv_em as u32).draw(
         name.as_str(),
         &mut v.monofont,
         &c.draw_state,
         transform, g
      );

      ii += 1;
   }
}
pub fn render_quests(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;
}

pub fn render_map(gm: &mut GameState, v: &mut WindowState, c: &graphics::context::Context, g: &mut G2d) {
   let mid_left = v.f_halfwidth() - 0.25 * v.f_em;

   let map_high = 3.5 * v.f_em;
   let map_left = 0.5 * v.f_em;
   let map_width = mid_left - 2.0*map_left;

   if let Some(_) = v.clicked {
      if 0.0 <= v.cursor[0] && v.cursor[0] <= (2.0*map_left+map_width) &&
         map_high <= v.cursor[1] {
         v.map_has_focus = true;
      } else {
         v.map_has_focus = false;
      }
   }

   let mut brightness_factor = gm.circuit(6.0);
   if brightness_factor < 2.0 {
      brightness_factor = (2.0 - brightness_factor) / 2.0;
      brightness_factor = brightness_factor * 0.1 + 0.9;
   } else {
      brightness_factor -= 2.0;
      brightness_factor = brightness_factor / 4.0;
      brightness_factor = brightness_factor * 0.1 + 0.9;
   }
   let bf = brightness_factor as f32;

   let tile_size = map_width / 21.0;
   let tile_gap  = 0.0;
   let mut min_i = 0;
   let mut min_j = 0;
   let mut max_i = 20;
   let mut max_j = 20;
   let (agent_x, agent_y) = gm.agent_position;
   let (target_x, target_y) = match gm.agent_move_target {
      Some((oi,oj)) => { (oi, oj) }
      None => { (0, 0) }
   };

   for i in min_i .. (max_i+1) {
      for j in min_j .. (max_j+1) {
         let relative_i = (i-10) as i32;
         let relative_j = (j-10) as i32;
         let absolute_i = agent_x + relative_i;
         let absolute_j = agent_y + relative_j;
         
         if (relative_i.pow(2) + relative_j.pow(2)) > 99 { continue; }

         if absolute_i < 0 || absolute_i >= (gm.board_width as i32) ||
            absolute_j < 0 || absolute_j >= (gm.board_height as i32) {
            continue;
         }

         let mut x = map_left + (i as f64) * (tile_gap + tile_size);
         let mut y = map_high + (j as f64) * (tile_gap + tile_size);

         let hovered = x<=v.cursor[0] && v.cursor[0]<=(x+tile_size) &&
                       y<=v.cursor[1] && v.cursor[1]<=(y+tile_size);

         if let Some(_) = v.clicked {
            if hovered {
               match (v.pressed("E".to_string()), gm.board_creature[ (absolute_j*gm.board_width + absolute_i) as usize ].clone()) {
                  (true,Some(creature)) => {
                     gm.agent_move_target = None;
                     gm.agent_engaged = Some((absolute_i, absolute_j, creature.clone()));
                  }
                  _ => {
                     gm.agent_move_target = Some((relative_i, relative_j));             
                     gm.agent_engaged = None;
                  }
               }
            }
         }

         let mut terrain_image = gm.board_terrain[ (absolute_j*gm.board_width + absolute_i) as usize ].clone();
         if terrain_image != "".to_string() {
            let mut terrain_img = "terrain_".to_string();
            terrain_img.push_str(terrain_image.as_str());
            terrain_img.push_str(".png");
            let aspect = tile_size / 512.0;
            let t = c.transform
                     .trans(x, y)
                     .scale(aspect, aspect);
            let terrain = v.texture(terrain_img.clone());
            image(&terrain, t, g);
         }

         match gm.board_items[ (absolute_j*gm.board_width + absolute_i) as usize ] {
            Some(ref ts) => {
               for ti in 0..ts.len() {
                  let ref item_sentence = ts[ti];
                  if let Word::Audio(ref itm_nm) = item_sentence[0] {
                     let mut item_name = "item_".to_string();
                     item_name.push_str( itm_nm.as_str() );
                     item_name.push_str(".png");
                     let aspect = tile_size / 512.0;
                     let t = c.transform
                        .trans(x, y)
                        .scale(aspect, aspect);
                     let item = v.texture(item_name.clone());
                     image(&item, t, g);
                  }
               }
            }
            None => {}
         }

         match gm.board_creature[ (absolute_j*gm.board_width + absolute_i) as usize ] {
            Some(ref ts) => {
               if let Word::Audio(ref cn) = ts[0] {
                  let mut creature_name = "avatar_".to_string();
                  creature_name.push_str(cn.as_str());
                  creature_name.push_str(".png");
                  let aspect = tile_size / 512.0;
                  let t = c.transform
                     .trans(x, y)
                     .scale(aspect, aspect);
                  let creature = v.texture(creature_name.clone());
                  image(&creature, t, g);
               }
            }
            None => {}
         }

         let opacity = 1.0;
         let mut tile_colour = [0.6*bf, 0.6*bf, 0.6*bf, opacity as f32];
         if (target_x != 0 || target_y != 0) && relative_i==target_x && relative_j==target_y {
            if terrain::tile_open(gm, absolute_i, absolute_j) {
               tile_colour = [0.4*bf, 0.9*bf, 0.4*bf, opacity as f32];
            } else {
               tile_colour = [0.9*bf, 0.9*bf, 0.4*bf, opacity as f32];
            }
            rectangle(tile_colour,
                [x, y, tile_size, tile_size],
                c.transform, g);
         } else if hovered {
            if terrain::tile_open(gm, absolute_i, absolute_j) {
               tile_colour = [0.9*bf, 0.9*bf, 0.4*bf, opacity as f32];
            } else {
               tile_colour = [0.9*bf, 0.4*bf, 0.4*bf, opacity as f32];
            }
            rectangle(tile_colour,
                [x, y, tile_size, tile_size],
                c.transform, g);
         } else if terrain_image == "".to_string() {
            rectangle(tile_colour,
                [x, y, tile_size, tile_size],
                c.transform, g);
         }

      }
   }

   let avatar_x = map_left + 10.0 * (tile_gap + tile_size);
   let avatar_y = map_high + 10.0 * (tile_gap + tile_size);
   let aspect = tile_size / 512.0;
   let t = c.transform
            .trans(avatar_x, avatar_y)
            .scale(aspect, aspect);

   let mut texture_name = "avatar_".to_string();
   texture_name.push_str( gm.agent_class.as_str() );
   texture_name.push_str( ".png" );
   let shield = v.texture(texture_name);
   image(&shield, t, g);

}
