#pragma once

#include <Resource/Image.h>
#include <Encoding/PNG.h>
#include "../Base.h"
#include "../File.h"

#pragma warning(push)
#pragma warning(disable:4250)

namespace gorgon {

	class Image;

	Image *LoadImage(Base *parent, File &File, std::istream &Data, int Size);

	class Image : virtual public gge::resource::Image, public Base {
		friend class Animation;
		friend Image *LoadImage(gorgon::Base *parent, File &File, std::istream &Data, int Size);
	public:
		Image() : gge::resource::Image() {			
		}

		Image(int Width, int Height, gge::graphics::ColorMode::Type Mode=gge::graphics::ColorMode::ARGB) : 
		gge::resource::Image(Width, Height, Mode) {
		}

		Image(gge::resource::Image &img) : gge::resource::Image(img) {			
		}

		virtual void Save(std::ostream &out) {
			auto start=WriteObjectStart(out, *this);

			if(Compression!=Image::Uncompressed && Compression!=Image::PNG) {
				throw std::runtime_error("Unsupported compression mode");
			}

			auto propstart=WriteSectionStart(out, gge::resource::GID::Image_Props);
			WriteTo(out, Width);
			WriteTo(out, Height);
			WriteTo(out, (int)Mode);
			WriteTo(out, (int)Compression);
			WriteTo(out, 0);
			WriteEnd(out, propstart);

			if(Compression==Image::Uncompressed) {
				int dsize=(int)Width*Height*gge::graphics::getBPP(Mode);
				auto datastart=WriteSectionStart(out, gge::resource::GID::Image_Data);
				out.write((char*)GetData(), dsize);
				WriteEnd(out, datastart);
			}
			else if(Compression==Image::PNG)
			{
				WriteTo(out, gge::resource::GID::Image_Cmp_Props);
				WriteTo(out, 4);
				WriteTo(out, gge::resource::GID::PNG);

				auto cmpstart=WriteSectionStart(out, gge::resource::GID::Image_Cmp_Data);
				gge::Byte *newdata=new gge::Byte[GetWidth()*GetHeight()*4];
				for(int i=0;i<GetWidth()*GetHeight();i++) {
					newdata[i*4+2]=Data[i*4+0];
					newdata[i*4+1]=Data[i*4+1];
					newdata[i*4+0]=Data[i*4+2];
					newdata[i*4+3]=Data[i*4+3];
				}
				gge::encoding::Png.Encode(newdata, out, GetWidth(), GetHeight());
				WriteEnd(out, cmpstart);
			}

			WriteEnd(out, start);
		}

		virtual void Prepare(gge::GGEMain &main, File &file) {
			gge::resource::File dummy;

			gge::resource::Image::Prepare(main, dummy);
		}

		gge::Byte *GetData() {
			return Data;
		}

		void SetCompression(Compressor compression) {
			Compression=compression;
		}

		Compressor GetCompression() const {
			return Compression;
		}

		virtual GID::Type GetGID() const {
			return gge::resource::Image::GetGID();
		}
	};
	
}

#pragma warning(pop)
