/*
 * Pixel Dungeon
 * Copyright (C) 2012-2015 Oleg Dolya
 *
 * Shattered Pixel Dungeon
 * Copyright (C) 2014-2019 Evan Debenham
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>
 */

package com.shatteredpixel.shatteredpixeldungeon.android.windows;

import android.app.Activity;
import android.graphics.Typeface;
import android.text.InputFilter;
import android.text.InputType;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidGraphics;
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.android.AndroidGame;
import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.shatteredpixel.shatteredpixeldungeon.ui.RedButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
import com.watabou.noosa.Game;

//This class makes use of the android EditText component to handle text input
//FIXME this window is currently android-specific, should generalize it
public class WndAndroidTextInput extends Window {

	private EditText textInput;

	private static final int WIDTH 			= 120;
	private static final int W_LAND_MULTI 	= 200; //in the specific case of multiline in landscape
	private static final int MARGIN 		= 2;
	private static final int BUTTON_HEIGHT	= 16;

	//default maximum lengths for inputted text
	private static final int MAX_LEN_SINGLE = 20;
	private static final int MAX_LEN_MULTI 	= 2000;

	public WndAndroidTextInput(String title, String initialValue, boolean multiLine, String posTxt, String negTxt){
		this( title, initialValue, multiLine ? MAX_LEN_MULTI : MAX_LEN_SINGLE, multiLine, posTxt, negTxt);
	}

	public WndAndroidTextInput(final String title, final String initialValue, final int maxLength,
	                           final boolean multiLine, final String posTxt, final String negTxt){
		super();

		//need to offset to give space for the soft keyboard
		if (PixelScene.landscape()) {
			offset( multiLine ? -45 : -45 );
		} else {
			offset( multiLine ? -60 : -45 );
		}

		final int width;
		if (PixelScene.landscape() && multiLine){
			width = W_LAND_MULTI; //more editing space for landscape users
		} else {
			width = WIDTH;
		}
		
		final RenderedTextBlock txtTitle = PixelScene.renderTextBlock( title, 9 );
		txtTitle.maxWidth( width );
		txtTitle.hardlight( Window.TITLE_COLOR );
		txtTitle.setPos( (width - txtTitle.width()) /2, 2);
		add(txtTitle);
		
		final RedButton positiveBtn = new RedButton( posTxt ) {
			@Override
			protected void onClick() {
				onSelect( true );
				hide();
			}
		};
		
		final RedButton negativeBtn;
		if (negTxt != null) {
			negativeBtn = new RedButton(negTxt) {
				@Override
				protected void onClick() {
					onSelect(false);
					hide();
				}
			};
		} else {
			negativeBtn = null;
		}
		
		((AndroidApplication)Gdx.app).runOnUiThread(new Runnable() {
			@Override
			public void run() {

				float pos = txtTitle.bottom() + 2*MARGIN;

				textInput = new EditText((AndroidApplication)Gdx.app);
				textInput.setText( initialValue );
				if (!SPDSettings.systemFont()){
					textInput.setTypeface( Typeface.createFromAsset(AndroidGame.instance.getAssets(), "fonts/pixel_font.ttf") );
				}
				textInput.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
				textInput.setInputType( InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES );

				//this accounts for the game resolution differing from the display resolution in power saver mode
				final float scaledZoom;
				scaledZoom = camera.zoom * (Game.dispWidth / (float)Game.width);

				//sets different visual style depending on whether this is a single or multi line input.
				final float inputHeight;
				if (multiLine) {

					textInput.setSingleLine(false);
					//This is equivalent to PixelScene.renderText(6)
					textInput.setTextSize( TypedValue.COMPLEX_UNIT_PX, 6*scaledZoom);
					//8 lines of text (+1 line for padding)
					inputHeight = 9*textInput.getLineHeight() / scaledZoom;

				} else {

					//sets to single line and changes enter key input to be the same as the positive button
					textInput.setSingleLine();
					textInput.setOnEditorActionListener( new EditText.OnEditorActionListener() {
						@Override
						public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
							onSelect(true);
							hide();
							return true;
						}
					});

					//doesn't let the keyboard take over the whole UI
					textInput.setImeOptions( EditorInfo.IME_FLAG_NO_EXTRACT_UI );

					//centers text
					textInput.setGravity(Gravity.CENTER);

					//This is equivalent to PixelScene.renderText(9)
					textInput.setTextSize( TypedValue.COMPLEX_UNIT_PX, 9*scaledZoom);
					//1 line of text (+1 line for padding)
					inputHeight = 2*textInput.getLineHeight() / scaledZoom;

				}

				//We haven't added the textInput yet, but we can anticipate its height at this point.
				pos += inputHeight + MARGIN;

				
				if (negTxt != null)
					positiveBtn.setRect( MARGIN, pos, (width - MARGIN * 3) / 2, BUTTON_HEIGHT );
				else
					positiveBtn.setRect( MARGIN, pos, width - MARGIN * 2, BUTTON_HEIGHT );
				add( positiveBtn );

				if (negTxt != null){
					negativeBtn.setRect( positiveBtn.right() + MARGIN, pos, (width - MARGIN * 3) / 2, BUTTON_HEIGHT );
					add( negativeBtn );
				}

				pos += BUTTON_HEIGHT + MARGIN;

				//The layout of the TextEdit is in display pixel space, not ingame pixel space
				// resize the window first so we can know the screen-space coordinates for the text input.
				resize( width, (int)pos );
				final int inputTop = (int)(camera.cameraToScreen(0, txtTitle.bottom() + 2*MARGIN).y * (Game.dispWidth / (float)Game.width));

				//The text input exists in a separate view ontop of the normal game view.
				// It visually appears to be a part of the game window but is infact a separate
				// UI element from the game entirely.
				FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
						(int)((width - MARGIN*2)*scaledZoom),
						(int)(inputHeight * scaledZoom),
						Gravity.CENTER_HORIZONTAL);
				layout.setMargins(0, inputTop, 0, 0);
				((AndroidApplication)Gdx.app).addContentView(textInput, layout);
			}
		});
	}

	public String getText(){
		return textInput.getText().toString().trim();
	}

	protected void onSelect( boolean positive ) {}

	@Override
	public void destroy() {
		super.destroy();
		if (textInput != null){
			((AndroidApplication)Gdx.app).runOnUiThread(new Runnable() {
				@Override
				public void run() {
					//make sure we remove the edit text and soft keyboard
					((ViewGroup) textInput.getParent()).removeView(textInput);

					InputMethodManager imm = (InputMethodManager)((AndroidApplication)Gdx.app).getSystemService(Activity.INPUT_METHOD_SERVICE);
					imm.hideSoftInputFromWindow(((AndroidGraphics)Gdx.app.getGraphics()).getView().getWindowToken(), 0);

					//Soft keyboard sometimes triggers software buttons, so make sure to reassert immersive
					ShatteredPixelDungeon.updateSystemUI();

					textInput = null;
				}
			});
		}
	}
	
	@Override
	public void onBackPressed() {
		//Do nothing, prevents accidentally losing writing
	}
}