/*******************************************************************************
 * Copyright 2014 Rafael Garcia Moreno.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package com.bladecoder.engine.ui;

import java.io.BufferedReader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.bladecoder.engine.assets.EngineAssetManager;
import com.bladecoder.engine.ui.UI.Screens;
import com.bladecoder.engine.util.DPIUtils;
import com.bladecoder.engine.util.EngineLogger;

public class CreditsScreen extends ScreenAdapter implements BladeScreen {
	private static final String CREDITS_FILENAME = "ui/credits";
	private static final float SPEED = 10 * DPIUtils.getSpacing(); // px/sec.

	// title and texts pair sequence
	private final List<String> credits = new ArrayList<>();

	private CreditScreenStyle style;

	private int stringHead = 0;
	private float scrollY = 0;

	private UI ui;

	private Music music;

	private final Map<String, Texture> images = new HashMap<>();

	private Viewport viewport;

	private final GlyphLayout layout = new GlyphLayout();

	private final InputProcessor inputProcessor = new InputAdapter() {
		@Override
		public boolean keyUp(int keycode) {
			if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK)
				ui.setCurrentScreen(Screens.MENU_SCREEN);

			return true;
		}

		@Override
		public boolean touchUp(int screenX, int screenY, int pointer, int button) {
			ui.setCurrentScreen(Screens.MENU_SCREEN);
			return true;
		}
	};

	@Override
	public void render(float delta) {
		final SpriteBatch batch = ui.getBatch();
		final int width = (int) viewport.getWorldWidth();
		final int height = (int) viewport.getWorldHeight();

		Gdx.gl.glClearColor(0, 0, 0, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

		batch.setProjectionMatrix(viewport.getCamera().combined);
		batch.begin();

		if (style.background != null) {
			style.background.draw(batch, 0, 0, width, height);
		}

		scrollY += delta * SPEED * EngineAssetManager.getInstance().getScale();

		float y = scrollY;

		if (stringHead >= credits.size())
			ui.setCurrentScreen(Screens.MENU_SCREEN);

		for (int i = stringHead; i < credits.size(); i++) {
			String s = credits.get(i);

			char type = 'c'; // types are 'c' -> credit, 't' -> title, 'i' -> image, 's' -> space, 'm' ->
								// music

			if (s.indexOf('#') != -1) {
				type = s.charAt(0);
				s = s.substring(2);
			}

			switch (type) {
			case 't':
				y = processCreditTitle(batch, width, height, y, i, s);
				break;
			case 'i':
				y = processCreditImage(batch, width, height, y, i, s);
				break;
			case 's':
				y = processCreditSpace(height, y, i, s);
				break;
			case 'm':
				processCreditMusic(s);
				credits.remove(i);
				i--;
				break;
			default:
				y = processCreditDefault(batch, width, height, y, i, s);
				break;
			}

			if (y < 0) {
				break;
			}
		}

		batch.end();
	}

	private float processCreditTitle(SpriteBatch batch, int width, int height, float y, int i, String s) {
		final float lineHeight = style.titleFont.getLineHeight();
		y -= lineHeight * 2;

		drawCenteredScreenX(batch, style.titleFont, s, y, width);
		y -= lineHeight;

		if (y > height + lineHeight) {
			stringHead = i + 1;
			scrollY -= lineHeight;
			scrollY -= lineHeight * 2;
		}
		return y;
	}

	private float processCreditImage(SpriteBatch batch, int width, int height, float y, int i, String s) {
		Texture img = images.get(s);
		final int lineHeight = img.getHeight();
		batch.draw(img, (width - img.getWidth()) / 2, y - lineHeight);

		y -= lineHeight;

		if (y > height) {
			stringHead = i + 1;
			scrollY -= lineHeight;
		}
		return y;
	}

	private float processCreditSpace(int height, float y, int i, String s) {
		int lineHeight = (int) (Integer.valueOf(s) * EngineAssetManager.getInstance().getScale());
		y -= lineHeight;

		if (y > height) {
			stringHead = i + 1;
			scrollY -= lineHeight;
		}
		return y;
	}

	private void processCreditMusic(final String s) {
		if (music != null)
			music.dispose();

		final String file = EngineAssetManager.getInstance().checkIOSSoundName("music/" + s);

		new Thread() {
			@Override
			public void run() {
				music = Gdx.audio.newMusic(EngineAssetManager.getInstance().getAsset(file));

				try {
					music.play();
					music.setVolume(0.5f);
				} catch (Exception e) {

					// DEAL WITH OPENAL BUG
					if (Gdx.app.getType() == ApplicationType.Desktop && e.getMessage().contains("40963")) {
						EngineLogger.debug("!!!!!!!!!!!!!!!!!!!!!!!ERROR playing music trying again...!!!!!!!!!!!!!!!");

						music = Gdx.audio.newMusic(EngineAssetManager.getInstance().getAsset(file));
						music.play();
						music.setVolume(0.5f);

						return;
					}

					EngineLogger.error("Error Playing music: " + file);
				}
			}
		}.start();
	}

	private float processCreditDefault(SpriteBatch batch, int width, int height, float y, int i, String s) {
		drawCenteredScreenX(batch, style.font, s, y, width);

		final float lineHeight = style.font.getLineHeight();
		y -= lineHeight;

		if (y > height + lineHeight) {
			stringHead = i + 1;
			scrollY -= lineHeight;
		}
		return y;
	}

	@Override
	public void resize(int width, int height) {
		viewport.update(width, height, true);
	}

	@Override
	public void dispose() {
		for (Texture t : images.values())
			t.dispose();

		images.clear();
		credits.clear();

		if (music != null) {
			music.stop();
			music.dispose();
			music = null;
		}
	}

	private void retrieveAssets() {
		style = ui.getSkin().get(CreditScreenStyle.class);

		final Locale locale = Locale.getDefault();

		String localeFilename = MessageFormat.format("{0}_{1}.txt", CREDITS_FILENAME, locale.getLanguage());

		if (!EngineAssetManager.getInstance().assetExists(localeFilename))
			localeFilename = MessageFormat.format("{0}.txt", CREDITS_FILENAME);

		BufferedReader reader = EngineAssetManager.getInstance().getAsset(localeFilename).reader(4096, "utf-8");

		try {
			String line;
			while ((line = reader.readLine()) != null) {
				credits.add(line);
			}
		} catch (Exception e) {
			EngineLogger.error(e.getMessage());

			ui.setCurrentScreen(Screens.MENU_SCREEN);
		}

		scrollY += style.titleFont.getLineHeight();

		// Load IMAGES
		for (String s : credits) {
			if (s.indexOf('#') != -1 && s.charAt(0) == 'i') {
				s = s.substring(2);

				Texture tex = new Texture(EngineAssetManager.getInstance().getResAsset("ui/" + s));
				tex.setFilter(TextureFilter.Linear, TextureFilter.Linear);

				images.put(s, tex);
			}
		}
	}

	@Override
	public void show() {
		retrieveAssets();
		Gdx.input.setInputProcessor(inputProcessor);

//		int wWidth = EngineAssetManager.getInstance().getResolution().portraitWidth;
//		int wHeight = EngineAssetManager.getInstance().getResolution().portraitHeight;

//		viewport = new ExtendViewport(wWidth, wHeight);
		viewport = new ScreenViewport();

		stringHead = 0;
		scrollY = 0;
	}

	@Override
	public void hide() {
		dispose();
	}

	@Override
	public void setUI(UI ui) {
		this.ui = ui;
	}

	public void drawCenteredScreenX(SpriteBatch batch, BitmapFont font, CharSequence str, float y, int viewportWidth) {
		float x = 0;

		layout.setText(font, str, Color.WHITE, viewportWidth, Align.center, true);

		// x = (viewportWidth - layout.width)/2;

		font.draw(batch, layout, x, y);
	}

	/**
	 * The style for the CreditsScreen
	 */
	public static class CreditScreenStyle {
		/**
		 * Optional.
		 */
		public Drawable background;
		/**
		 * if 'bg' not specified try to load the bgFile
		 */
		public String bgFile;
		public BitmapFont titleFont;
		public BitmapFont font;

		public CreditScreenStyle() {
		}

		public CreditScreenStyle(CreditScreenStyle style) {
			background = style.background;
			bgFile = style.bgFile;
			titleFont = style.titleFont;
			font = style.font;
		}
	}
}