/*
 * Copyright (C) 2017 - 2019 | Wurst-Imperium | All rights reserved.
 *
 * This source code is subject to the terms of the GNU General Public
 * License, version 3. If a copy of the GPL was not distributed with this
 * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
 */
package net.wurstclient.forge.clickgui;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;

import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.ScaledResolution;
import net.wurstclient.forge.Category;
import net.wurstclient.forge.ForgeWurst;
import net.wurstclient.forge.Hack;
import net.wurstclient.forge.HackList;
import net.wurstclient.forge.compatibility.WMinecraft;
import net.wurstclient.forge.settings.Setting;
import net.wurstclient.forge.utils.JsonUtils;

public final class ClickGui
{
	private final ArrayList<Window> windows = new ArrayList<>();
	private final ArrayList<Popup> popups = new ArrayList<>();
	private final Path windowsFile;
	
	private float[] bgColor = new float[3];
	private float[] acColor = new float[3];
	private float opacity;
	private int maxHeight;
	
	private String tooltip;
	
	public ClickGui(Path windowsFile)
	{
		this.windowsFile = windowsFile;
	}
	
	public void init(HackList hax)
	{
		LinkedHashMap<Category, Window> windowMap = new LinkedHashMap<>();
		for(Category category : Category.values())
			windowMap.put(category, new Window(category.getName()));
		
		for(Hack hack : hax.getRegistry())
			if(hack.getCategory() != null)
				windowMap.get(hack.getCategory()).add(new HackButton(hack));
			
		windows.addAll(windowMap.values());
		
		Window uiSettings = new Window("UI Settings");
		for(Setting setting : hax.clickGuiHack.getSettings().values())
			uiSettings.add(setting.getComponent());
		windows.add(uiSettings);
		
		for(Window window : windows)
			window.setMinimized(true);
		
		windows.add(hax.radarHack.getWindow());
		
		int x = 5;
		int y = 5;
		ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
		for(Window window : windows)
		{
			window.pack();
			
			if(x + window.getWidth() + 5 > sr.getScaledWidth())
			{
				x = 5;
				y += 18;
			}
			
			window.setX(x);
			window.setY(y);
			x += window.getWidth() + 5;
		}
		
		JsonObject json;
		try(BufferedReader reader = Files.newBufferedReader(windowsFile))
		{
			json = JsonUtils.jsonParser.parse(reader).getAsJsonObject();
			
		}catch(NoSuchFileException e)
		{
			saveWindows();
			return;
			
		}catch(Exception e)
		{
			System.out.println("Failed to load " + windowsFile.getFileName());
			e.printStackTrace();
			
			saveWindows();
			return;
		}
		
		for(Window window : windows)
		{
			JsonElement jsonWindow = json.get(window.getTitle());
			if(jsonWindow == null || !jsonWindow.isJsonObject())
				continue;
			
			JsonElement jsonX = jsonWindow.getAsJsonObject().get("x");
			if(jsonX.isJsonPrimitive() && jsonX.getAsJsonPrimitive().isNumber())
				window.setX(jsonX.getAsInt());
			
			JsonElement jsonY = jsonWindow.getAsJsonObject().get("y");
			if(jsonY.isJsonPrimitive() && jsonY.getAsJsonPrimitive().isNumber())
				window.setY(jsonY.getAsInt());
			
			JsonElement jsonMinimized =
				jsonWindow.getAsJsonObject().get("minimized");
			if(jsonMinimized.isJsonPrimitive()
				&& jsonMinimized.getAsJsonPrimitive().isBoolean())
				window.setMinimized(jsonMinimized.getAsBoolean());
			
			JsonElement jsonPinned = jsonWindow.getAsJsonObject().get("pinned");
			if(jsonPinned.isJsonPrimitive()
				&& jsonPinned.getAsJsonPrimitive().isBoolean())
				window.setPinned(jsonPinned.getAsBoolean());
		}
		
		saveWindows();
	}
	
	private void saveWindows()
	{
		JsonObject json = new JsonObject();
		
		for(Window window : windows)
		{
			if(window.isClosable())
				continue;
			
			JsonObject jsonWindow = new JsonObject();
			jsonWindow.addProperty("x", window.getX());
			jsonWindow.addProperty("y", window.getY());
			jsonWindow.addProperty("minimized", window.isMinimized());
			jsonWindow.addProperty("pinned", window.isPinned());
			json.add(window.getTitle(), jsonWindow);
		}
		
		try(BufferedWriter writer = Files.newBufferedWriter(windowsFile))
		{
			JsonUtils.prettyGson.toJson(json, writer);
			
		}catch(IOException e)
		{
			System.out.println("Failed to save " + windowsFile.getFileName());
			e.printStackTrace();
		}
	}
	
	public void handleMouseClick(int mouseX, int mouseY, int mouseButton)
	{
		boolean popupClicked =
			handlePopupMouseClick(mouseX, mouseY, mouseButton);
		
		if(!popupClicked)
			handleWindowMouseClick(mouseX, mouseY, mouseButton);
		
		for(Popup popup : popups)
			if(popup.getOwner().getParent().isClosing())
				popup.close();
			
		windows.removeIf(w -> w.isClosing());
		popups.removeIf(p -> p.isClosing());
	}
	
	private boolean handlePopupMouseClick(int mouseX, int mouseY,
		int mouseButton)
	{
		for(int i = popups.size() - 1; i >= 0; i--)
		{
			Popup popup = popups.get(i);
			Component owner = popup.getOwner();
			Window parent = owner.getParent();
			
			int x0 = parent.getX() + owner.getX();
			int y0 =
				parent.getY() + 13 + parent.getScrollOffset() + owner.getY();
			
			int x1 = x0 + popup.getX();
			int y1 = y0 + popup.getY();
			int x2 = x1 + popup.getWidth();
			int y2 = y1 + popup.getHeight();
			
			if(mouseX < x1 || mouseY < y1)
				continue;
			if(mouseX >= x2 || mouseY >= y2)
				continue;
			
			int cMouseX = mouseX - x0;
			int cMouseY = mouseY - y0;
			popup.handleMouseClick(cMouseX, cMouseY, mouseButton);
			
			popups.remove(i);
			popups.add(popup);
			return true;
		}
		
		return false;
	}
	
	private void handleWindowMouseClick(int mouseX, int mouseY, int mouseButton)
	{
		for(int i = windows.size() - 1; i >= 0; i--)
		{
			Window window = windows.get(i);
			if(window.isInvisible())
				continue;
			
			int x1 = window.getX();
			int y1 = window.getY();
			int x2 = x1 + window.getWidth();
			int y2 = y1 + window.getHeight();
			int y3 = y1 + 13;
			
			if(mouseX < x1 || mouseY < y1)
				continue;
			if(mouseX >= x2 || mouseY >= y2)
				continue;
			
			if(mouseY < y3)
				handleTitleBarMouseClick(window, mouseX, mouseY, mouseButton);
			else if(!window.isMinimized())
			{
				window.validate();
				
				int cMouseX = mouseX - x1;
				int cMouseY = mouseY - y3;
				
				if(window.isScrollingEnabled() && mouseX >= x2 - 3)
					handleScrollbarMouseClick(window, cMouseX, cMouseY,
						mouseButton);
				else
				{
					if(window.isScrollingEnabled())
						cMouseY -= window.getScrollOffset();
					
					handleComponentMouseClick(window, cMouseX, cMouseY,
						mouseButton);
				}
				
			}else
				continue;
			
			windows.remove(i);
			windows.add(window);
			break;
		}
	}
	
	private void handleTitleBarMouseClick(Window window, int mouseX, int mouseY,
		int mouseButton)
	{
		if(mouseButton != 0)
			return;
		
		if(mouseY < window.getY() + 2 || mouseY >= window.getY() + 11)
		{
			window.startDragging(mouseX, mouseY);
			return;
		}
		
		int x3 = window.getX() + window.getWidth();
		
		if(window.isClosable())
		{
			x3 -= 11;
			if(mouseX >= x3 && mouseX < x3 + 9)
			{
				window.close();
				return;
			}
		}
		
		if(window.isPinnable())
		{
			x3 -= 11;
			if(mouseX >= x3 && mouseX < x3 + 9)
			{
				window.setPinned(!window.isPinned());
				saveWindows();
				return;
			}
		}
		
		if(window.isMinimizable())
		{
			x3 -= 11;
			if(mouseX >= x3 && mouseX < x3 + 9)
			{
				window.setMinimized(!window.isMinimized());
				saveWindows();
				return;
			}
		}
		
		window.startDragging(mouseX, mouseY);
	}
	
	private void handleScrollbarMouseClick(Window window, int mouseX,
		int mouseY, int mouseButton)
	{
		if(mouseButton != 0)
			return;
		
		if(mouseX >= window.getWidth() - 1)
			return;
		
		double outerHeight = window.getHeight() - 13;
		double innerHeight = window.getInnerHeight();
		double maxScrollbarHeight = outerHeight - 2;
		int scrollbarY =
			(int)(outerHeight * (-window.getScrollOffset() / innerHeight) + 1);
		int scrollbarHeight =
			(int)(maxScrollbarHeight * outerHeight / innerHeight);
		
		if(mouseY < scrollbarY || mouseY >= scrollbarY + scrollbarHeight)
			return;
		
		window.startDraggingScrollbar(window.getY() + 13 + mouseY);
	}
	
	private void handleComponentMouseClick(Window window, int mouseX,
		int mouseY, int mouseButton)
	{
		for(int i2 = window.countChildren() - 1; i2 >= 0; i2--)
		{
			Component c = window.getChild(i2);
			
			if(mouseX < c.getX() || mouseY < c.getY())
				continue;
			if(mouseX >= c.getX() + c.getWidth()
				|| mouseY >= c.getY() + c.getHeight())
				continue;
			
			c.handleMouseClick(mouseX, mouseY, mouseButton);
			break;
		}
	}
	
	public void render(int mouseX, int mouseY, float partialTicks)
	{
		GL11.glDisable(GL11.GL_CULL_FACE);
		GL11.glDisable(GL11.GL_TEXTURE_2D);
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
		GL11.glShadeModel(GL11.GL_SMOOTH);
		GL11.glLineWidth(1);
		
		// scrolling
		int dWheel = Mouse.getDWheel();
		if(dWheel != 0)
			for(int i = windows.size() - 1; i >= 0; i--)
			{
				Window window = windows.get(i);
				
				if(!window.isScrollingEnabled() || window.isMinimized()
					|| window.isInvisible())
					continue;
				
				if(mouseX < window.getX() || mouseY < window.getY() + 13)
					continue;
				if(mouseX >= window.getX() + window.getWidth()
					|| mouseY >= window.getY() + window.getHeight())
					continue;
				
				int scroll = window.getScrollOffset() + dWheel / 16;
				scroll = Math.min(scroll, 0);
				scroll = Math.max(scroll,
					-window.getInnerHeight() + window.getHeight() - 13);
				window.setScrollOffset(scroll);
				break;
			}
		
		tooltip = null;
		for(Window window : windows)
		{
			if(window.isInvisible())
				continue;
			
			// dragging
			if(window.isDragging())
				if(Mouse.isButtonDown(0))
					window.dragTo(mouseX, mouseY);
				else
				{
					window.stopDragging();
					saveWindows();
				}
			
			// scrollbar dragging
			if(window.isDraggingScrollbar())
				if(Mouse.isButtonDown(0))
					window.dragScrollbarTo(mouseY);
				else
					window.stopDraggingScrollbar();
				
			renderWindow(window, mouseX, mouseY, partialTicks);
		}
		
		GL11.glDisable(GL11.GL_TEXTURE_2D);
		for(Popup popup : popups)
		{
			Component owner = popup.getOwner();
			Window parent = owner.getParent();
			
			int x1 = parent.getX() + owner.getX();
			int y1 =
				parent.getY() + 13 + parent.getScrollOffset() + owner.getY();
			
			GL11.glPushMatrix();
			GL11.glTranslated(x1, y1, 0);
			
			int cMouseX = mouseX - x1;
			int cMouseY = mouseY - y1;
			popup.render(cMouseX, cMouseY);
			
			GL11.glPopMatrix();
		}
		
		// tooltip
		if(tooltip != null)
		{
			String[] lines = tooltip.split("\n");
			Minecraft mc = Minecraft.getMinecraft();
			FontRenderer fr = WMinecraft.getFontRenderer();
			
			int tw = 0;
			int th = lines.length * fr.FONT_HEIGHT;
			for(String line : lines)
			{
				int lw = fr.getStringWidth(line);
				if(lw > tw)
					tw = lw;
			}
			int sw = mc.currentScreen.width;
			int sh = mc.currentScreen.height;
			
			int xt1 = mouseX + tw + 11 <= sw ? mouseX + 8 : mouseX - tw - 8;
			int xt2 = xt1 + tw + 3;
			int yt1 = mouseY + th - 2 <= sh ? mouseY - 4 : mouseY - th - 4;
			int yt2 = yt1 + th + 2;
			
			// background
			GL11.glDisable(GL11.GL_TEXTURE_2D);
			GL11.glColor4f(bgColor[0], bgColor[1], bgColor[2], 0.75F);
			GL11.glBegin(GL11.GL_QUADS);
			GL11.glVertex2i(xt1, yt1);
			GL11.glVertex2i(xt1, yt2);
			GL11.glVertex2i(xt2, yt2);
			GL11.glVertex2i(xt2, yt1);
			GL11.glEnd();
			
			// outline
			GL11.glColor4f(acColor[0], acColor[1], acColor[2], 0.5F);
			GL11.glBegin(GL11.GL_LINE_LOOP);
			GL11.glVertex2i(xt1, yt1);
			GL11.glVertex2i(xt1, yt2);
			GL11.glVertex2i(xt2, yt2);
			GL11.glVertex2i(xt2, yt1);
			GL11.glEnd();
			
			// text
			GL11.glEnable(GL11.GL_TEXTURE_2D);
			for(int i = 0; i < lines.length; i++)
				fr.drawString(lines[i], xt1 + 2, yt1 + 2 + i * fr.FONT_HEIGHT,
					0xffffff);
		}
		
		GL11.glEnable(GL11.GL_CULL_FACE);
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		GL11.glDisable(GL11.GL_BLEND);
	}
	
	public void renderPinnedWindows(float partialTicks)
	{
		GL11.glDisable(GL11.GL_CULL_FACE);
		GL11.glDisable(GL11.GL_TEXTURE_2D);
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
		GL11.glShadeModel(GL11.GL_SMOOTH);
		GL11.glLineWidth(1);
		
		for(Window window : windows)
			if(window.isPinned() && !window.isInvisible())
				renderWindow(window, Integer.MIN_VALUE, Integer.MIN_VALUE,
					partialTicks);
			
		GL11.glEnable(GL11.GL_CULL_FACE);
		GL11.glEnable(GL11.GL_TEXTURE_2D);
	}
	
	public void updateColors()
	{
		HackList hax = ForgeWurst.getForgeWurst().getHax();
		
		opacity = hax.clickGuiHack.getOpacity();
		bgColor = hax.clickGuiHack.getBgColor();
		maxHeight = hax.clickGuiHack.getMaxHeight();
		
		if(hax.rainbowUiHack.isEnabled())
		{
			float x = System.currentTimeMillis() % 2000 / 1000F;
			acColor[0] = 0.5F + 0.5F * (float)Math.sin(x * Math.PI);
			acColor[1] = 0.5F + 0.5F * (float)Math.sin((x + 4F / 3F) * Math.PI);
			acColor[2] = 0.5F + 0.5F * (float)Math.sin((x + 8F / 3F) * Math.PI);
		}else
			acColor = hax.clickGuiHack.getAcColor();
	}
	
	private void renderWindow(Window window, int mouseX, int mouseY,
		float partialTicks)
	{
		int x1 = window.getX();
		int y1 = window.getY();
		int x2 = x1 + window.getWidth();
		int y2 = y1 + window.getHeight();
		int y3 = y1 + 13;
		
		if(window.isMinimized())
			y2 = y3;
		
		if(mouseX >= x1 && mouseY >= y1 && mouseX < x2 && mouseY < y2)
			tooltip = null;
		
		GL11.glDisable(GL11.GL_TEXTURE_2D);
		
		if(!window.isMinimized())
		{
			window.setMaxHeight(maxHeight);
			window.validate();
			
			// scrollbar
			if(window.isScrollingEnabled())
			{
				int xs1 = x2 - 3;
				int xs2 = xs1 + 2;
				int xs3 = x2;
				
				double outerHeight = y2 - y3;
				double innerHeight = window.getInnerHeight();
				double maxScrollbarHeight = outerHeight - 2;
				double scrollbarY =
					outerHeight * (-window.getScrollOffset() / innerHeight) + 1;
				double scrollbarHeight =
					maxScrollbarHeight * outerHeight / innerHeight;
				
				int ys1 = y3;
				int ys2 = y2;
				int ys3 = ys1 + (int)scrollbarY;
				int ys4 = ys3 + (int)scrollbarHeight;
				
				// window background
				GL11.glColor4f(bgColor[0], bgColor[1], bgColor[2], opacity);
				GL11.glBegin(GL11.GL_QUADS);
				GL11.glVertex2i(xs2, ys1);
				GL11.glVertex2i(xs2, ys2);
				GL11.glVertex2i(xs3, ys2);
				GL11.glVertex2i(xs3, ys1);
				GL11.glVertex2i(xs1, ys1);
				GL11.glVertex2i(xs1, ys3);
				GL11.glVertex2i(xs2, ys3);
				GL11.glVertex2i(xs2, ys1);
				GL11.glVertex2i(xs1, ys4);
				GL11.glVertex2i(xs1, ys2);
				GL11.glVertex2i(xs2, ys2);
				GL11.glVertex2i(xs2, ys4);
				GL11.glEnd();
				
				boolean hovering = mouseX >= xs1 && mouseY >= ys3
					&& mouseX < xs2 && mouseY < ys4;
				
				// scrollbar
				GL11.glColor4f(acColor[0], acColor[1], acColor[2],
					hovering ? opacity * 1.5F : opacity);
				GL11.glBegin(GL11.GL_QUADS);
				GL11.glVertex2i(xs1, ys3);
				GL11.glVertex2i(xs1, ys4);
				GL11.glVertex2i(xs2, ys4);
				GL11.glVertex2i(xs2, ys3);
				GL11.glEnd();
				
				// outline
				GL11.glColor4f(acColor[0], acColor[1], acColor[2], 0.5F);
				GL11.glBegin(GL11.GL_LINE_LOOP);
				GL11.glVertex2i(xs1, ys3);
				GL11.glVertex2i(xs1, ys4);
				GL11.glVertex2i(xs2, ys4);
				GL11.glVertex2i(xs2, ys3);
				GL11.glEnd();
			}
			
			int x3 = x1 + 2;
			int x4 = window.isScrollingEnabled() ? x2 - 3 : x2;
			int x5 = x4 - 2;
			int y4 = y3 + window.getScrollOffset();
			
			// window background
			// left & right
			GL11.glColor4f(bgColor[0], bgColor[1], bgColor[2], opacity);
			GL11.glBegin(GL11.GL_QUADS);
			GL11.glVertex2i(x1, y3);
			GL11.glVertex2i(x1, y2);
			GL11.glVertex2i(x3, y2);
			GL11.glVertex2i(x3, y3);
			GL11.glVertex2i(x5, y3);
			GL11.glVertex2i(x5, y2);
			GL11.glVertex2i(x4, y2);
			GL11.glVertex2i(x4, y3);
			GL11.glEnd();
			
			if(window.isScrollingEnabled())
			{
				ScaledResolution sr =
					new ScaledResolution(Minecraft.getMinecraft());
				int sf = sr.getScaleFactor();
				GL11.glScissor(x1 * sf,
					(int)((sr.getScaledHeight_double() - y2) * sf),
					window.getWidth() * sf, (y2 - y3) * sf);
				GL11.glEnable(GL11.GL_SCISSOR_TEST);
			}
			GL11.glPushMatrix();
			GL11.glTranslated(x1, y4, 0);
			
			GL11.glColor4f(bgColor[0], bgColor[1], bgColor[2], opacity);
			GL11.glBegin(GL11.GL_QUADS);
			
			// window background
			// between children
			int xc1 = 2;
			int xc2 = x5 - x1;
			for(int i = 0; i < window.countChildren(); i++)
			{
				int yc1 = window.getChild(i).getY();
				int yc2 = yc1 - 2;
				GL11.glVertex2i(xc1, yc2);
				GL11.glVertex2i(xc1, yc1);
				GL11.glVertex2i(xc2, yc1);
				GL11.glVertex2i(xc2, yc2);
			}
			
			// window background
			// bottom
			int yc1;
			if(window.countChildren() == 0)
				yc1 = 0;
			else
			{
				Component lastChild =
					window.getChild(window.countChildren() - 1);
				yc1 = lastChild.getY() + lastChild.getHeight();
			}
			int yc2 = yc1 + 2;
			GL11.glVertex2i(xc1, yc2);
			GL11.glVertex2i(xc1, yc1);
			GL11.glVertex2i(xc2, yc1);
			GL11.glVertex2i(xc2, yc2);
			
			GL11.glEnd();
			
			// render children
			int cMouseX = mouseX - x1;
			int cMouseY = mouseY - y4;
			for(int i = 0; i < window.countChildren(); i++)
				window.getChild(i).render(cMouseX, cMouseY, partialTicks);
			
			GL11.glPopMatrix();
			if(window.isScrollingEnabled())
				GL11.glDisable(GL11.GL_SCISSOR_TEST);
		}
		
		// window outline
		GL11.glColor4f(acColor[0], acColor[1], acColor[2], 0.5F);
		GL11.glBegin(GL11.GL_LINE_LOOP);
		GL11.glVertex2i(x1, y1);
		GL11.glVertex2i(x1, y2);
		GL11.glVertex2i(x2, y2);
		GL11.glVertex2i(x2, y1);
		GL11.glEnd();
		
		if(!window.isMinimized())
		{
			// title bar outline
			GL11.glBegin(GL11.GL_LINES);
			GL11.glVertex2i(x1, y3);
			GL11.glVertex2i(x2, y3);
			GL11.glEnd();
		}
		
		// title bar buttons
		int x3 = x2;
		int y4 = y1 + 2;
		int y5 = y3 - 2;
		boolean hoveringY = mouseY >= y4 && mouseY < y5;
		
		if(window.isClosable())
		{
			x3 -= 11;
			int x4 = x3 + 9;
			boolean hovering = hoveringY && mouseX >= x3 && mouseX < x4;
			renderCloseButton(x3, y4, x4, y5, hovering);
		}
		
		if(window.isPinnable())
		{
			x3 -= 11;
			int x4 = x3 + 9;
			boolean hovering = hoveringY && mouseX >= x3 && mouseX < x4;
			renderPinButton(x3, y4, x4, y5, hovering, window.isPinned());
		}
		
		if(window.isMinimizable())
		{
			x3 -= 11;
			int x4 = x3 + 9;
			boolean hovering = hoveringY && mouseX >= x3 && mouseX < x4;
			renderMinimizeButton(x3, y4, x4, y5, hovering,
				window.isMinimized());
		}
		
		// title bar background
		// above & below buttons
		GL11.glColor4f(acColor[0], acColor[1], acColor[2], opacity);
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glVertex2i(x3, y1);
		GL11.glVertex2i(x3, y4);
		GL11.glVertex2i(x2, y4);
		GL11.glVertex2i(x2, y1);
		GL11.glVertex2i(x3, y5);
		GL11.glVertex2i(x3, y3);
		GL11.glVertex2i(x2, y3);
		GL11.glVertex2i(x2, y5);
		GL11.glEnd();
		
		// title bar background
		// behind title
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glVertex2i(x1, y1);
		GL11.glVertex2i(x1, y3);
		GL11.glVertex2i(x3, y3);
		GL11.glVertex2i(x3, y1);
		GL11.glEnd();
		
		// window title
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		GL11.glColor4f(1, 1, 1, 1);
		FontRenderer fontRenderer = WMinecraft.getFontRenderer();
		String title =
			fontRenderer.trimStringToWidth(window.getTitle(), x3 - x1);
		fontRenderer.drawString(title, x1 + 2, y1 + 3, 0xf0f0f0);
	}
	
	private void renderTitleBarButton(int x1, int y1, int x2, int y2,
		boolean hovering)
	{
		int x3 = x2 + 2;
		
		// button background
		GL11.glColor4f(bgColor[0], bgColor[1], bgColor[2],
			hovering ? opacity * 1.5F : opacity);
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glVertex2i(x1, y1);
		GL11.glVertex2i(x1, y2);
		GL11.glVertex2i(x2, y2);
		GL11.glVertex2i(x2, y1);
		GL11.glEnd();
		
		// background between buttons
		GL11.glColor4f(acColor[0], acColor[1], acColor[2], opacity);
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glVertex2i(x2, y1);
		GL11.glVertex2i(x2, y2);
		GL11.glVertex2i(x3, y2);
		GL11.glVertex2i(x3, y1);
		GL11.glEnd();
		
		// button outline
		GL11.glColor4f(acColor[0], acColor[1], acColor[2], 0.5F);
		GL11.glBegin(GL11.GL_LINE_LOOP);
		GL11.glVertex2i(x1, y1);
		GL11.glVertex2i(x1, y2);
		GL11.glVertex2i(x2, y2);
		GL11.glVertex2i(x2, y1);
		GL11.glEnd();
	}
	
	private void renderMinimizeButton(int x1, int y1, int x2, int y2,
		boolean hovering, boolean minimized)
	{
		renderTitleBarButton(x1, y1, x2, y2, hovering);
		
		double xa1 = x1 + 1;
		double xa2 = (x1 + x2) / 2.0;
		double xa3 = x2 - 1;
		double ya1;
		double ya2;
		
		if(minimized)
		{
			ya1 = y1 + 3;
			ya2 = y2 - 2.5;
			GL11.glColor4f(0, hovering ? 1 : 0.85F, 0, 1);
			
		}else
		{
			ya1 = y2 - 3;
			ya2 = y1 + 2.5;
			GL11.glColor4f(hovering ? 1 : 0.85F, 0, 0, 1);
		}
		
		// arrow
		GL11.glBegin(GL11.GL_TRIANGLES);
		GL11.glVertex2d(xa1, ya1);
		GL11.glVertex2d(xa3, ya1);
		GL11.glVertex2d(xa2, ya2);
		GL11.glEnd();
		
		// outline
		GL11.glColor4f(0.0625F, 0.0625F, 0.0625F, 0.5F);
		GL11.glBegin(GL11.GL_LINE_LOOP);
		GL11.glVertex2d(xa1, ya1);
		GL11.glVertex2d(xa3, ya1);
		GL11.glVertex2d(xa2, ya2);
		GL11.glEnd();
	}
	
	private void renderPinButton(int x1, int y1, int x2, int y2,
		boolean hovering, boolean pinned)
	{
		renderTitleBarButton(x1, y1, x2, y2, hovering);
		float h = hovering ? 1 : 0.85F;
		
		if(pinned)
		{
			double xk1 = x1 + 2;
			double xk2 = x2 - 2;
			double xk3 = x1 + 1;
			double xk4 = x2 - 1;
			double yk1 = y1 + 2;
			double yk2 = y2 - 2;
			double yk3 = y2 - 0.5;
			
			// knob
			GL11.glColor4f(h, 0, 0, 0.5F);
			GL11.glBegin(GL11.GL_QUADS);
			GL11.glVertex2d(xk1, yk1);
			GL11.glVertex2d(xk2, yk1);
			GL11.glVertex2d(xk2, yk2);
			GL11.glVertex2d(xk1, yk2);
			GL11.glVertex2d(xk3, yk2);
			GL11.glVertex2d(xk4, yk2);
			GL11.glVertex2d(xk4, yk3);
			GL11.glVertex2d(xk3, yk3);
			GL11.glEnd();
			
			double xn1 = x1 + 3.5;
			double xn2 = x2 - 3.5;
			double yn1 = y2 - 0.5;
			double yn2 = y2;
			
			// needle
			GL11.glColor4f(h, h, h, 1);
			GL11.glBegin(GL11.GL_QUADS);
			GL11.glVertex2d(xn1, yn1);
			GL11.glVertex2d(xn2, yn1);
			GL11.glVertex2d(xn2, yn2);
			GL11.glVertex2d(xn1, yn2);
			GL11.glEnd();
			
			// outlines
			GL11.glColor4f(0.0625F, 0.0625F, 0.0625F, 0.5F);
			GL11.glBegin(GL11.GL_LINE_LOOP);
			GL11.glVertex2d(xk1, yk1);
			GL11.glVertex2d(xk2, yk1);
			GL11.glVertex2d(xk2, yk2);
			GL11.glVertex2d(xk1, yk2);
			GL11.glEnd();
			GL11.glBegin(GL11.GL_LINE_LOOP);
			GL11.glVertex2d(xk3, yk2);
			GL11.glVertex2d(xk4, yk2);
			GL11.glVertex2d(xk4, yk3);
			GL11.glVertex2d(xk3, yk3);
			GL11.glEnd();
			GL11.glBegin(GL11.GL_LINE_LOOP);
			GL11.glVertex2d(xn1, yn1);
			GL11.glVertex2d(xn2, yn1);
			GL11.glVertex2d(xn2, yn2);
			GL11.glVertex2d(xn1, yn2);
			GL11.glEnd();
			
		}else
		{
			double xk1 = x2 - 3.5;
			double xk2 = x2 - 0.5;
			double xk3 = x2 - 3;
			double xk4 = x1 + 3;
			double xk5 = x1 + 2;
			double xk6 = x2 - 2;
			double xk7 = x1 + 1;
			double yk1 = y1 + 0.5;
			double yk2 = y1 + 3.5;
			double yk3 = y2 - 3;
			double yk4 = y1 + 3;
			double yk5 = y1 + 2;
			double yk6 = y2 - 2;
			double yk7 = y2 - 1;
			
			// knob
			GL11.glColor4f(0, h, 0, 1);
			GL11.glBegin(GL11.GL_QUADS);
			GL11.glVertex2d(xk1, yk1);
			GL11.glVertex2d(xk2, yk2);
			GL11.glVertex2d(xk3, yk3);
			GL11.glVertex2d(xk4, yk4);
			GL11.glVertex2d(xk5, yk5);
			GL11.glVertex2d(xk6, yk6);
			GL11.glVertex2d(xk3, yk7);
			GL11.glVertex2d(xk7, yk4);
			GL11.glEnd();
			
			double xn1 = x1 + 3;
			double xn2 = x1 + 4;
			double xn3 = x1 + 1;
			double yn1 = y2 - 4;
			double yn2 = y2 - 3;
			double yn3 = y2 - 1;
			
			// needle
			GL11.glColor4f(h, h, h, 1);
			GL11.glBegin(GL11.GL_TRIANGLES);
			GL11.glVertex2d(xn1, yn1);
			GL11.glVertex2d(xn2, yn2);
			GL11.glVertex2d(xn3, yn3);
			GL11.glEnd();
			
			// outlines
			GL11.glColor4f(0.0625F, 0.0625F, 0.0625F, 0.5F);
			GL11.glBegin(GL11.GL_LINE_LOOP);
			GL11.glVertex2d(xk1, yk1);
			GL11.glVertex2d(xk2, yk2);
			GL11.glVertex2d(xk3, yk3);
			GL11.glVertex2d(xk4, yk4);
			GL11.glEnd();
			GL11.glBegin(GL11.GL_LINE_LOOP);
			GL11.glVertex2d(xk5, yk5);
			GL11.glVertex2d(xk6, yk6);
			GL11.glVertex2d(xk3, yk7);
			GL11.glVertex2d(xk7, yk4);
			GL11.glEnd();
			GL11.glBegin(GL11.GL_LINE_LOOP);
			GL11.glVertex2d(xn1, yn1);
			GL11.glVertex2d(xn2, yn2);
			GL11.glVertex2d(xn3, yn3);
			GL11.glEnd();
		}
	}
	
	private void renderCloseButton(int x1, int y1, int x2, int y2,
		boolean hovering)
	{
		renderTitleBarButton(x1, y1, x2, y2, hovering);
		
		double xc1 = x1 + 2;
		double xc2 = x1 + 3;
		double xc3 = x2 - 2;
		double xc4 = x2 - 3;
		double xc5 = x1 + 3.5;
		double xc6 = (x1 + x2) / 2.0;
		double xc7 = x2 - 3.5;
		double yc1 = y1 + 3;
		double yc2 = y1 + 2;
		double yc3 = y2 - 3;
		double yc4 = y2 - 2;
		double yc5 = y1 + 3.5;
		double yc6 = (y1 + y2) / 2.0;
		double yc7 = y2 - 3.5;
		
		// cross
		GL11.glColor4f(hovering ? 1 : 0.85F, 0, 0, 1);
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glVertex2d(xc1, yc1);
		GL11.glVertex2d(xc2, yc2);
		GL11.glVertex2d(xc3, yc3);
		GL11.glVertex2d(xc4, yc4);
		GL11.glVertex2d(xc3, yc1);
		GL11.glVertex2d(xc4, yc2);
		GL11.glVertex2d(xc6, yc5);
		GL11.glVertex2d(xc7, yc6);
		GL11.glVertex2d(xc6, yc7);
		GL11.glVertex2d(xc5, yc6);
		GL11.glVertex2d(xc1, yc3);
		GL11.glVertex2d(xc2, yc4);
		GL11.glEnd();
		
		// outline
		GL11.glColor4f(0.0625F, 0.0625F, 0.0625F, 0.5F);
		GL11.glBegin(GL11.GL_LINE_LOOP);
		GL11.glVertex2d(xc1, yc1);
		GL11.glVertex2d(xc2, yc2);
		GL11.glVertex2d(xc6, yc5);
		GL11.glVertex2d(xc4, yc2);
		GL11.glVertex2d(xc3, yc1);
		GL11.glVertex2d(xc7, yc6);
		GL11.glVertex2d(xc3, yc3);
		GL11.glVertex2d(xc4, yc4);
		GL11.glVertex2d(xc6, yc7);
		GL11.glVertex2d(xc2, yc4);
		GL11.glVertex2d(xc1, yc3);
		GL11.glVertex2d(xc5, yc6);
		GL11.glEnd();
	}
	
	public float[] getBgColor()
	{
		return bgColor;
	}
	
	public float[] getAcColor()
	{
		return acColor;
	}
	
	public float getOpacity()
	{
		return opacity;
	}
	
	public void setTooltip(String tooltip)
	{
		this.tooltip = tooltip;
	}
	
	public void addWindow(Window window)
	{
		windows.add(window);
	}
	
	public void addPopup(Popup popup)
	{
		popups.add(popup);
	}
}