#ifndef RENDERER_HPP
#define RENDERER_HPP

#include "config.h"

#include "render_device.hpp"

#include "image.hpp"

#include "graphic_object.hpp"

// mypair
#include "common.hpp"
#include "config.hpp"

#ifdef c_music
#include "audio_s.hpp"
#endif

#include <string>
#include <queue>
#include <map>
#include <iostream>

#define X_DISPLAY_MISSING

#define UGLY_FONT_FLICKER_HACK

#include <Imlib2.h>

class Render
{
private:
  static Render* instance;

  Config *conf;
#ifdef c_music
  Audio_s *audio_s;
#endif

  int width;
  int height;

  void create_scaled_image(const std::string& in_file, 
			   const std::string& out_file, 
			   std::string format, 
			   int max_x, int max_y);

  Image temp;

  class queue_obj
  {
  public:
    queue_obj(const std::string& p, Imlib_Image i, int o, Scaling s, 
	      double scale_f_w, double scale_f_h)
      : path(p), image(i), orientation(o), scaleable(s), count(0),
	scale_factor_w(scale_f_w), scale_factor_h(scale_f_h)
    {}

    std::string path;
    Imlib_Image image;
    int orientation;
    Scaling scaleable;
    double scale_factor_w;
    double scale_factor_h;
    int count;
  };

  typedef std::vector<queue_obj> image_queue;
  image_queue scaled_images;

  typedef std::map<std::string, Imlib_Font> font_map;
  font_map fonts;

  Imlib_Image current_nonblur;

  void remove_overlapping_objects();

  bool last_draw_overlay;

  Image prev_overlay;
  void last_overlay();
  void last_not_overlay();

protected:
  Render();

public:

  bool set_font(const std::string& font_name);

  void set_theme();
  void set_audio_state();

  Image current;
  Image previous;

  std::string default_path;

  ost::Mutex image_mut;

  class rect
  {
  public:
    int x, y, w, h;
    rect()
    {}
    rect(int x_, int y_, int w_, int h_) 
      : x(x_), y(y_), w(w_), h(h_)
    {}

    int area()
    { return w*h; }

    bool operator > (const rect& r)
    { return x < r.x && y < r.y && x + w >= r.x + r.w && y + h >= r.y + r.h; }

    bool operator >= (const rect& r)
    { return x <= r.x && y <= r.y && x + w >= r.x + r.w && y + h >= r.y + r.h; }

    std::string to_string() const
    {
      return (conv::itos(x) + ":" + conv::itos(y) + ":" + conv::itos(w) + ":" + conv::itos(h));
    }
  };

  typedef std::vector<std::pair<GObj*, rect> > graph_objs;
  graph_objs objects;
  std::vector<rect> draw_rects;

  // automaticly takes the image_mutex
  void prepare_new_image();

  void draw(const std::string& module, bool overlay = false);
  void complete_draw();
  void complete_redraw();

  bool contains(const rect& outer, const rect& inner);
  bool equal(GObj *lhs, GObj *rhs);

  // helper function
  bool intersect_check(int x1, int w1, int y1, int h1,
		       int x2, int w2, int y2, int h2);

  bool intersect(GObj *lhs, GObj *rhs);
  bool intersect(const rect& lhs, const rect& rhs);
  bool intersect(const rect& lhs, GObj *rhs, rect& r);
  bool intersect(GObj *lhs, GObj *rhs, rect& r);

  Imlib_Image image_loader(const std::string& path, Scaling scaleable, 
			   double scale_factor_h, double scale_factor_w, int orientation);

  // x,y,width,height in background rendered at x_in_d,y_in_d
  void image_rectangle(GObj *g, int x, int y, 
		       int width, int height, int x_in_d, int y_in_d);

  Render_device *device;

  static Render* get_instance();

  void blur();
  void clear();
  Imlib_Image new_imlib_image();

  std::string image_get_fullpath(const std::string& path, int max_width, int max_height);
  std::pair<int, int> image_dimensions(const std::string& path, bool *transparent);
  bool image_fullscreen_dimensions(const std::string& path, bool zoom, int orientation, 
				   int zoom_level, int zoom_pos,
				   int &real_x, int &real_y, int &real_w, int &real_h,
				   int &w, int &h, bool *transparent);
  void image(const std::string& path, int x, int y, int w, int h, Scaling scaleable, 
	     double scale_factor_h, double scale_factor_w, int orientation);
  void image_fullpath(const std::string& path, int x, int y, int max_width, int max_height, 
		      bool border, Scaling scaleable, double scale_factor_h, double scale_factor_w, int orientation);
  void image_fullscreen_zoom(const std::string& path, int orientation, int zoom_level, int zoom_position, 
			     int zoom_vertical_levels, int zoom_horizontal_levels, int x, int y, 
			     int scaled_w, int scaled_h, Scaling scaleable, double scale_factor_h, double scale_factor_w);
  void image_fullscreen(const std::string& path, int orientation, int x, int y, int scaled_w, int scaled_h,
			Scaling scaleable, double scale_factor_h, double scale_factor_w);

  void create_scaled_image_wrapper(const std::string& path, int max_x, int max_y);

  void text(const std::string& text, const std::string& font, int x, int y, int r, int g, int b);
  void text_part(const std::string& text, const std::string& font, int r, int g, int b,  
		 int x, int y, int total_w, int total_h, const rect& r);
  void rectangle(int x, int y, int width, int height, int r, int g, int b, int a);
};

#endif
