/*
 * custom_content_actor.cpp
 *
 * Copyright 2016 Ian Martin <martin_id@vodafone.co.nz>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 *
 */

#include <gtkmm/window.h>
#include <gtkmm/box.h>
#include <gtkmm/button.h>

#include <gdkmm/pixbuf.h>
#include <glibmm/error.h>
#include <cairo.h>
#include <clutter/clutter.h>
#include <cairomm/context.h>

#include <clutter-gtkmm.h>
#include <iostream>

namespace
{

class StageWindow : public Gtk::Window
{
public:
  StageWindow();
  virtual ~StageWindow();

private:
  Clutter::Gtk::Embed* embed_;
  Glib::RefPtr<Clutter::Stage> stage_;
  Glib::RefPtr<Clutter::Actor> arect, brect;
  bool canvas_draw( const ::Cairo::RefPtr< ::Cairo::Context >& cr, int width, int height);

  void on_button_clicked();
  static bool on_stage_button_press(Clutter::ButtonEvent* event);
  void Set_Content(std::string file_location);

};

StageWindow::StageWindow()
:
  embed_(0)
{
  std::cout << "Stage constructor." << std::endl;

  Gtk::Box *const box = new Gtk::VBox(false, 6);
  add(*Gtk::manage(box));

  embed_ = new Clutter::Gtk::Embed();
  box->pack_start(*Gtk::manage(embed_), Gtk::PACK_EXPAND_WIDGET);
  embed_->set_size_request(200, 200);

  stage_ = embed_->get_stage();
  stage_->reference();
  stage_->set_background_color(Clutter::Color(0, 0, 0)); // black
  stage_->signal_button_press_event().connect(&StageWindow::on_stage_button_press);

	//Create an actor and add it to the stage:
  arect = Clutter::Actor::create();
  arect->set_position(20, 20);
  arect->set_size(100, 100);
  Set_Content("docs/icons/home.png");

  //Add a second actor, this time using the Canvas Interface:
  Glib::RefPtr <Clutter::Canvas > canvas = Clutter::Canvas::create();
  brect = Clutter::Actor::create();
  //brect->set_background_color(Clutter::Color(255, 0, 0));
  brect->set_content(canvas);
  brect->set_position(20, 200);
  canvas->set_size(100, 100);
  brect->set_size( 200, 200);

  stage_->add_child(brect);
  stage_->add_child(arect);
  arect->show();
  brect->show();

  canvas->signal_draw().connect(sigc::mem_fun( *this, &StageWindow::canvas_draw) );
  show_all();

  canvas->invalidate();
  stage_->show();
}

StageWindow::~StageWindow()
{}

bool StageWindow::on_stage_button_press(Clutter::ButtonEvent* event)
{
  float x = 0;
  float y = 0;
  // TODO: Wrap properly
  clutter_event_get_coords(reinterpret_cast<Clutter::Event*>(event), &x, &y);

  std::cout << "Stage clicked at (" << x << ", " << y << ")\n";

  return true; // stop further handling of this event
}

void StageWindow::Set_Content(std::string file_location)
/**
 * This function is a little problematic in that it requires that the program is
 * only run from its own parent directory
 * */
{
  Glib::RefPtr <Gdk::Pixbuf > pb = Gdk::Pixbuf::create_from_file(file_location);
  Glib::RefPtr < Clutter::Image > img = Clutter::Image::create();
  try{
    img->set_data( pb->get_pixels(),
          pb->get_has_alpha() ? COGL_PIXEL_FORMAT_RGBA_8888 :COGL_PIXEL_FORMAT_RGB_888,
          pb->get_width(), pb->get_height(), pb->get_rowstride() );
  }
  catch(Glib::Error& ex){
    std::cerr << "Error loading pixbuf. " << ex.what() << std::endl;
  }
  arect->set_content(img);
}

bool StageWindow::canvas_draw( const ::Cairo::RefPtr< ::Cairo::Context >& cr,
    int width, int height)
/**
 * Draw a very basic version of the home icon referenced above.
 * */
{

   // Left side of roof:
   cr->save();
    cr->scale(  width/ 36, height/ 36 );

    cr->save();
    cr->begin_new_path();
    cr->move_to(18, 1);
    cr->line_to(2, 14);
    cr->line_to(0, 22);
    cr->line_to(3, 23);
    cr->line_to(18, 9);
    cr->close_path();
    cr->set_source_rgb( 0.8, 0.4, 0.4 );
    cr->fill();
  cr->restore();

  //Right side roof:
  cr->save();
 //   cr->scale(  width/ 36, height/ 36 );
    cr->begin_new_path();
    cr->move_to(18, 1);
    cr->line_to(34, 14);
    cr->line_to(35, 22);
    cr->line_to( 33, 23);
    cr->line_to(18, 9);
    cr->close_path();
    cr->set_source_rgb(0.8, 0.1, 0.1 );
    cr->fill();
  cr->restore();

  // body of house:
  cr->save();
 //   cr->scale(  width/ 36, height/ 36 );
    cr->begin_new_path();
    cr->move_to(5, 21);
    cr->line_to(18, 9);
    cr->line_to(31, 21);
    cr->line_to(31, 35);
    cr->line_to(5, 35);
    cr->close_path();
    cr->set_source_rgb(1.0, 1.0, 1.0 );  //white
    cr->fill();

  cr->restore();

  //bottom of the house
  cr->save();
    cr->move_to(31, 21);
    cr->line_to(31, 35);
    cr->line_to(5, 35);
    cr->line_to(5, 21);
    cr->set_line_join(Cairo::LINE_JOIN_ROUND);
    cr->set_line_width(0.5);
    cr->set_source_rgb(0.2, 0.2, 0.2 );
    cr->stroke();
  cr->restore();

  // door
  cr->save();
    cr->move_to(8, 35);
    cr->line_to(8, 23);
    cr->line_to(16, 23);
    cr->line_to(16, 35);
    cr->close_path();
    cr->set_source_rgb(0.4, 0.4, 0.4 );
    cr->fill();
  cr->restore();

  //doorhandle:
    cr->save();
   cr->arc(14, 30, 1, 0, 2 * M_PI);
    cr->set_source_rgb(0.9, 0.9, 0 );

    cr->fill();
  cr->restore();

  //window:
  cr->save();
    cr->rectangle(20, 22, 8, 8 );
    cr->set_source_rgb(0.3, 0.3, 0.99 );

    cr->fill();
  cr->restore();


  return true;
}

} // anonymous namespace


int main(int argc, char** argv)
{
  try
  {
    Clutter::Gtk::init(&argc, &argv);
    Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

    StageWindow window;
     window.set_size_request(400, 600);

    app->run(window);
  }
  catch (const Glib::Error& error)
  {
    std::cerr << "Exception: " << error.what() << std::endl;
    return 1;
  }

  return 0;
}
