/* $Id: about.cpp 13056 2006-08-09 15:57:51Z zookeeper $ */
/*
   Copyright (C) 2003 by David White <davidnwhite@verizon.net>
   Part of the Battle for Wesnoth Project http://www.wesnoth.org/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#include "about.hpp"
#include "display.hpp"
#include "font.hpp"
#include "game_config.hpp"
#include "gettext.hpp"
#include "marked-up_text.hpp"
#include "video.hpp"
#include "show_dialog.hpp"

namespace about
{

  config about_list = config();
  std::map<std::string , std::string> images;
  std::string images_default;

std::vector<std::string> get_text(std::string campaign) {
	static const char *credits[] = {
		"_" N_("+Developers"),
		"-   David White (Sirp)",
		"-   *",
		"-   Alfredo Beaumont (ziberpunk)",
		"-   András Salamon (ott)",
		"-   Benoît Timbert (Noyga)",
		"-   Bram Ridder (Morloth)",
		"-   Bruno Wolff III",
		"-   Cedric Duval",
		"-   Cyril Bouthors (CyrilB)",
		"-   Dominic Bolin (Xan)",
		"-   Guillaume Melquiond (silene)",
		"-   Isaac Clerencia",
		"-   Jan Zvánovec (jaz)",
		"-   Jérémy Rosen (Boucman)",
		"-   John B. Messerly",
		"-   John W. C. McNabb (Darth Fool)",
		"-   Jon Daniel (forcemstr)",
		"-   Jörg Hinrichs (Yogi Bear/YogiHH)",
		"-   Justin Zaun (jzaun)",
		"-   J.R. Blain (Cowboy)",
		"-   Kristoffer Erlandsson (erl)",
		"-   Maksim Orlovich (SadEagle)",
		"-   Nicolas Weeger (Ryo)",
		"-   Patrick Parker (Sapient)",
		"-   Philippe Plantier (Ayin)",
		"-   Rusty Russell (rusty)",
		"-   Yann Dirson",
		"-   Zas",
		"_" N_("+General Purpose Administrators"),
		"-   Crossbow/Miyo",
		"-   Isaac Clerencia",
	};

	std::vector< std::string > res;
	size_t len = sizeof(credits) / sizeof(*credits);
	res.reserve(len);

	const config::child_list& children = about::about_list.get_children("about");

	for(config::child_list::const_iterator cc = children.begin(); cc != children.end(); ++cc) {
	  //just finished a particular campaign
	  if(campaign.size() && campaign == (**cc)["id"]){
	    std::string title=(**cc)["title"];
	    if(title.size()){
	      title = N_("+" + title);
	      res.push_back(title);
	    }
	    std::vector<std::string> lines=utils::split((**cc)["text"],'\n');
	    for(std::vector<std::string>::iterator line=lines.begin();
		line != lines.end(); line++){
	      if((*line)[0] == '+' && (*line).size()>1){
		*line = N_("+  " + (*line).substr(1,(*line).size()-1));
	      }else{
		*line = "-  " + *line;
	      }
	      if(line->size()){
		if ((*line)[0] == '_')
		  *line = gettext(line->substr(1,line->size()-1).c_str());
		res.push_back(*line);
	      }
	    }
	  }
	}

	for(size_t i = 0; i < len; ++i) {
		const char *s = credits[i];
		if (s[0] == '_')
		  s = gettext(s + 1);
		res.push_back(s);
	}

	for(config::child_list::const_iterator acc = children.begin(); acc != children.end(); ++acc) {
	  std::string title=(**acc)["title"];
	  if(title.size()){
	    title = N_("+" + title);
	    res.push_back(title);
	  }
	  std::vector<std::string> lines=utils::split((**acc)["text"],'\n');
	  for(std::vector<std::string>::iterator line=lines.begin();
	      line != lines.end(); line++){
	    if((*line)[0] == '+' && (*line).size()>1){
	      *line = N_("+  " + (*line).substr(1,(*line).size()-1));
	    }else{
	      *line = "-  " + *line;
	    }
	    if(line->size()){
	      if ((*line)[0] == '_')
		*line = gettext(line->substr(1,line->size()-1).c_str());
	      res.push_back(*line);
	    }
	  }
	}

	return res;
}

void set_about(const config& cfg){
	config::child_list about = cfg.get_children("about");
	for(config::child_list::const_iterator A = about.begin(); A != about.end(); A++) {
		config AA = (**A);
		about_list.add_child("about",AA);
		if(!AA["images"].empty()){
			if(images_default.empty()){
				images_default=AA["images"];
			}else{
				images_default+=","+AA["images"];
			}
		}
	}
	config::child_list campaigns = cfg.get_children("campaign");
	for(config::child_list::const_iterator C = campaigns.begin(); C != campaigns.end(); C++) {
		config::child_list about = (**C).get_children("about");
		if(about.size()){
			config temp;
			std::string text;
			std::string title;
			std::string campaign=(**C)["id"];
			title=(**C)["name"];
			temp["title"]=title;
			temp["id"]=(**C)["id"];
			for(config::child_list::const_iterator A = about.begin(); A != about.end(); A++) {
				config AA = (**A);
				std::string subtitle=AA["title"];
				if(subtitle.size()){
				if (subtitle[0] == '_')
						subtitle = gettext(subtitle.substr(1,subtitle.size()-1).c_str());
					text += "+" + subtitle + "\n";
				}
				std::vector<std::string> lines=utils::split(AA["text"],'\n');
				for(std::vector<std::string>::iterator line=lines.begin();
			line != lines.end(); line++){
					text+="    "+(*line)+"\n";
				}

				if(!AA["images"].empty()){
					if(images[campaign].empty()){
						images[campaign]=AA["images"];
					}else{
						images[campaign]+=","+AA["images"];
					}
				}
		}
			temp["text"]=text;
			about_list.add_child("about",temp);
		}
	}
}

void show_about(display &disp, std::string campaign)
{
	CVideo &video = disp.video();
	std::vector<std::string> text = about::get_text(campaign);
	SDL_Rect rect = {0, 0, video.getx(), video.gety()};

	const surface_restorer restorer(&video, rect);

	// Clear the screen
	draw_solid_tinted_rectangle(0,0,video.getx()-1,video.gety()-1,
	                                 0,0,0,1.0,video.getSurface());
	update_whole_screen();

	std::vector<std::string> image_list;
	if(campaign.size() && !images[campaign].empty()){
		image_list=utils::split(images[campaign]);
	}else{
		image_list=utils::split(images_default,',',utils::STRIP_SPACES);
	}
	surface map_image(scale_surface(image::get_image(image_list[0],image::UNSCALED), disp.x(), disp.y()));
	if(! map_image){
		image_list[0]=game_config::game_title;
		map_image=surface(scale_surface(image::get_image(image_list[0],image::UNSCALED), disp.x(), disp.y()));
	}

	SDL_Rect map_rect;
	map_rect.x = video.getx()/2 - map_image->w/2;
	map_rect.y = video.gety()/2 - map_image->h/2;
	map_rect.w = map_image->w;
	map_rect.h = map_image->h;

	gui::button close(video,_("Close"));
	close.set_location((video.getx()/2)-(close.width()/2), video.gety() - 30);
	close.set_volatile(true);

	//substitute in the correct control characters for '+' and '-'
	std::string before_header(2, ' ');
	before_header[0] = font::LARGE_TEXT;
	for(unsigned i = 0; i < text.size(); ++i) {
		std::string &s = text[i];
		if (s.empty()) continue;
		char &first = s[0];
		if (first == '-')
			first = font::SMALL_TEXT;
		else if (first == '+') {
			first = font::LARGE_TEXT;
			text.insert(text.begin() + i, before_header);
			++i;
		}
	}
	text.insert(text.begin(), 10, before_header);

	int startline = 0;

	// the following two lines should be changed if the image of the map is changed
	const int top_margin = 60;		// distance from top of map image to top of scrolling text
	const int bottom_margin = 40;	// distance from bottom of scrolling text to bottom of map image

	int offset = 0;
	bool is_new_line = true;

	int first_line_height = 0;

	// the following rectangles define the top, middle and bottom of the background image
	// the upper and lower part is later used to mask the upper and lower line of scrolling text
	SDL_Rect upper_src = {0, 0, map_rect.w, top_margin};
	SDL_Rect upper_dest = {map_rect.x, map_rect.y, map_rect.w, top_margin};
	SDL_Rect middle_src = {0, top_margin, map_rect.w, map_rect.h - top_margin - bottom_margin};
	SDL_Rect middle_dest = {map_rect.x, map_rect.y + top_margin, map_rect.w, map_rect.h - top_margin - bottom_margin};
	SDL_Rect lower_src = {0, map_rect.h - bottom_margin, map_rect.w, bottom_margin};
	SDL_Rect lower_dest = {map_rect.x, map_rect.y + map_rect.h - bottom_margin, map_rect.w, bottom_margin};

	CKey key;
	bool last_escape;
	int image_count=0;
	do {
		last_escape = key[SDLK_ESCAPE] != 0;

		// check to see if background image has changed
		if(text.size() && (image_count < ((startline*(int)image_list.size())/(int)text.size()))){
			image_count++;
			surface temp=surface(scale_surface(image::get_image(image_list[image_count],image::UNSCALED), disp.x(), disp.y()));
			map_image=temp?temp:map_image;
		}
		// draw map to screen, thus erasing all text

		SDL_BlitSurface(map_image,&middle_src,video.getSurface(),&middle_dest);
		std::string style = "mainmenu";

          gui::draw_dialog_frame(map_rect.x + map_rect.w * 3/32, map_rect.y + top_margin, map_rect.w * 13 / 16, map_rect.h - top_margin - bottom_margin,disp.video(),&style);
		// draw one screen full of text
		const int line_spacing = 5;
		int y = map_rect.y + top_margin - offset;
		int line = startline;
		int cur_line = 0;

		do {
//			SDL_Rect tr2 = font::draw_text(&video,screen_area(),font::SIZE_XLARGE,font::BLACK_COLOUR,
//						text[line], map_rect.x + map_rect.w / 8 + 1,y + 1);
			SDL_Rect tr = font::draw_text(&video,screen_area(),font::SIZE_XLARGE,font::NORMAL_COLOUR,
					              text[line], map_rect.x + map_rect.w / 8,y);

			if(is_new_line) {
				is_new_line = false;
				first_line_height = tr.h + line_spacing;
			}
			line++;
			if(size_t(line) > text.size()-1)
				line = 0;
			y += tr.h + line_spacing;
			cur_line++;
		} while(y<map_rect.y + map_rect.h - bottom_margin);

		// performs the actual scrolling
		const int scroll_speed = 4;		// scroll_speed*50 = speed of scroll in pixel per second

		offset += scroll_speed;
		if(offset>=first_line_height) {
			offset -= first_line_height;
			is_new_line = true;
			startline++;
			if(size_t(startline) == text.size()){
				startline = 0;
				image_count = -1;
			}
		}

		// mask off the upper and lower half of the map,
		// so text will scroll into view rather than
		// suddenly appearing out of nowhere
		SDL_BlitSurface(map_image,&upper_src,video.getSurface(),&upper_dest);
		SDL_BlitSurface(map_image,&lower_src,video.getSurface(),&lower_dest);

		// handle events
		events::pump();
		events::raise_process_event();
		events::raise_draw_event();

		// update screen and wait, so the text does not scroll too fast
		update_rect(map_rect);
		close.set_dirty(true);
		disp.flip();
		disp.delay(20);

	} while(!close.pressed() && (last_escape || !key[SDLK_ESCAPE]));

}

}
