/*
 * SpriteComponent.h
 *
 *  Created on: Feb 22, 2020
 *      Author: ayoungblood
 */

#ifndef SRC_ECS_SPRITECOMPONENT_H_
#define SRC_ECS_SPRITECOMPONENT_H_

#include "Components.h"
#include <SDL2/SDL.h>
#include "../assetmgr/TextureManager.h"
#include "Animation.h"
#include <map>
#include "../assetmgr/AssetManager.h"
#include "../cjson/cJSON.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <string>

class SpriteComponent : public Component
{
private:
	TransformComponent *transform;
	SDL_Texture *texture;
	SDL_Rect srcRect, destRect;
	char letter;
	int frames = 0;
	int speed = 100;
	int letterWidth, letterHeight;
	int scale = 1;

public:
    enum SpriteType : std::size_t
    {
    	spriteUIL0,
        spriteUIL1,
        spriteText,
    	spriteObject,
    	spriteTileMap,
        spriteBackground,
    	spriteActor,
        spriteAnimation,
        spriteAtlas
    };
    SpriteType spriteType;
	int animIndex = 0;
	bool ui = false;
	std::map<const char*, Animation> animations;

	SDL_RendererFlip spriteFlip = SDL_FLIP_NONE;

//	SpriteComponent() = default;
	SpriteComponent(std::string id, SpriteType sType)
	{
        spriteType = sType;
		setTex(id);
	}

// 	One initializer to rule them all
    SpriteComponent(std::string id, SpriteType sType, std::string json)
    {
        spriteType = sType;
        if(sType == spriteAnimation)
        {            
            std::ifstream fin(json);
            
            if(fin.is_open()){
            } else {
                std::cout<<"json file is NOT open"<<std::endl;
            }
            
            if(fin.fail()){
                std::cout<<"json file open fail"<<std::endl;
            } else{
            }
            
            std::ifstream jsonText(json);
            std::ostringstream tmp;
            tmp << jsonText.rdbuf();
            std::string aJson = tmp.str();
            cJSON * animJson = cJSON_Parse(aJson.c_str());
            cJSON * meta = cJSON_GetObjectItem(animJson, "meta");
            cJSON * frameTags = cJSON_GetObjectItem(meta,"frameTags");
            int tagsCount = cJSON_GetArraySize(frameTags);
            
            for (int t = 0; t < tagsCount; t++)
            {
                cJSON * animItem = cJSON_GetArrayItem(frameTags,t);
                cJSON * nameJson = cJSON_GetObjectItem(animItem, "name");
                const char * name = cJSON_Print(nameJson);
                int fromFrame = cJSON_GetObjectItem(animItem, "from")->valueint;
                int toFrame = cJSON_GetObjectItem(animItem, "to")->valueint;
                Animation anim = Animation(fromFrame,toFrame,100);
                animations.emplace(name, anim);
                Play(name);
            }

        Animation idle = Animation(0,3,100);
        animations.emplace("Idle", idle);
        Animation walk = Animation(1,3,100);
        animations.emplace("Walk", walk);
        Animation jump = Animation(2,1,100);
        animations.emplace("Jump", jump);
        Animation fall = Animation(3,1,100);
        animations.emplace("Fall",fall);
        Play("Idle");
        }
        setTex(id);
    }
	
	SpriteComponent(std::string id, SpriteType sType, SDL_Rect srcR, SDL_Rect destR)
    {
		spriteType = sType;
		setTex(id);
		srcRect = srcR;
		destRect = destR;
	}

	~SpriteComponent()
	{
		SDL_DestroyTexture(texture);
	}

	void setTex(std::string id)
	{
		texture = Game::assets->GetTexture(id);
	}

	void init() override
	{
		transform = &entity->getComponent<TransformComponent>();

        switch(spriteType)
        {
            case spriteUIL0: case spriteUIL1: case spriteBackground:
                break;
            case spriteActor: case spriteAnimation: case spriteAtlas: case spriteObject: case spriteTileMap:
                srcRect.x = srcRect.y = 0;
                srcRect.w = transform->width;
                srcRect.h = transform->height;
                break;
            default:
                break;
        }
	}

	void update() override
	{
        switch(spriteType)
        {
            case spriteUIL0: case spriteUIL1: case spriteText: case spriteBackground:
                destRect.x = static_cast<int>(transform->position.x);
                destRect.y = static_cast<int>(transform->position.y);
                break;
            case spriteActor: case spriteObject: case spriteAtlas:
                srcRect.y = animIndex * transform->height;
                destRect.x = static_cast<int>(transform->position.x) - Game::camera.x;
                destRect.y = static_cast<int>(transform->position.y) - Game::camera.y;
                destRect.w = transform->width * transform->scale;
                destRect.h = transform->height * transform->scale;
                break;
            case spriteTileMap:
                break;
            case spriteAnimation:
                srcRect.x = srcRect.w * static_cast<int>((SDL_GetTicks()/speed) % frames);
                srcRect.y = animIndex * transform->height;
                destRect.x = static_cast<int>(transform->position.x) - Game::camera.x;
                destRect.y = static_cast<int>(transform->position.y) - Game::camera.y;
                destRect.w = transform->width * transform->scale;
                destRect.h = transform->height * transform->scale;
                break;
            default:
                break;
        }
	}

	void draw() override
	{
		TextureManager::Draw(texture, srcRect, destRect, spriteFlip);
	}

	void Play(const char* animName)
	{
		frames = animations[animName].frames;
		animIndex = animations[animName].index;
		speed = animations[animName].speed;
	}

};

#endif /* SRC_ECS_SPRITECOMPONENT_H_ */
