package net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.server;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.text.DateFormat;
import java.util.Properties;
import java.util.logging.Level;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.EaglerXBungee;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.auth.DefaultAuthSystem;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.config.EaglerListenerConfig;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.config.EaglerRateLimiter;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.config.RateLimitStatus;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.server.web.HttpMemoryCache;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.server.web.HttpWebServer;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.sqlite.EaglerDrivers;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.TextComponent;

/**
 * Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 */
public class HttpHandshakeHandler extends ChannelInboundHandlerAdapter {
	
	private static final byte[] error429Bytes = "<h3>429 Too Many Requests<br /><small>(Try again later)</small></h3>".getBytes(StandardCharsets.UTF_8);
	
	private final EaglerListenerConfig conf;
	
	public HttpHandshakeHandler(EaglerListenerConfig conf) {
		this.conf = conf;
	}
	
	public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
		if (msg instanceof HttpRequest) {
			EaglerConnectionInstance pingTracker = ctx.channel().attr(EaglerPipeline.CONNECTION_INSTANCE).get();
			HttpRequest req = (HttpRequest) msg;
			HttpHeaders headers = req.headers();
			
			String rateLimitHost = null;
			
			if(conf.isForwardIp()) {
				String str = headers.get(conf.getForwardIpHeader());
				if(str != null) {
					rateLimitHost = str.split(",", 2)[0];
					try {
						ctx.channel().attr(EaglerPipeline.REAL_ADDRESS).set(InetAddress.getByName(rateLimitHost));
					}catch(UnknownHostException ex) {
						EaglerXBungee.logger().warning("[" + ctx.channel().remoteAddress() + "]: Connected with an invalid '" + conf.getForwardIpHeader() + "' header, disconnecting...");
						ctx.close();
						return;
					}
				}else {
					EaglerXBungee.logger().warning("[" + ctx.channel().remoteAddress() + "]: Connected without a '" + conf.getForwardIpHeader() + "' header, disconnecting...");
					ctx.close();
					return;
				}
			}else {
				SocketAddress addr = ctx.channel().remoteAddress();
				if(addr instanceof InetSocketAddress) {
					rateLimitHost = ((InetSocketAddress) addr).getAddress().getHostAddress();
				}
			}
			
			EaglerRateLimiter ipRateLimiter = conf.getRatelimitIp();
			RateLimitStatus ipRateLimit = RateLimitStatus.OK;
			
			if(ipRateLimiter != null && rateLimitHost != null) {
				ipRateLimit = ipRateLimiter.rateLimit(rateLimitHost);
			}
			
			if(ipRateLimit == RateLimitStatus.LOCKED_OUT) {
				ctx.close();
				return;
			}
			
			if(headers.get(HttpHeaderNames.CONNECTION) != null && headers.get(HttpHeaderNames.CONNECTION).toLowerCase().contains("upgrade") &&
					"websocket".equalsIgnoreCase(headers.get(HttpHeaderNames.UPGRADE))) {
				
				String origin = headers.get(HttpHeaderNames.ORIGIN);
				if(origin != null) {
					ctx.channel().attr(EaglerPipeline.ORIGIN).set(origin);
				}
				
				//TODO: origin blacklist
				
				if(ipRateLimit == RateLimitStatus.OK) {
					ctx.channel().attr(EaglerPipeline.HOST).set(headers.get(HttpHeaderNames.HOST));
					ctx.pipeline().replace(this, "HttpWebSocketHandler", new HttpWebSocketHandler(conf));
				}
				
				WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
						"ws://" + headers.get(HttpHeaderNames.HOST) + req.uri(), null, true, 0xFFFFF);
				WebSocketServerHandshaker hs = wsFactory.newHandshaker(req);
				if(hs != null) {
					pingTracker.isWebSocket = true;
					ChannelFuture future = hs.handshake(ctx.channel(), req);
					if(ipRateLimit != RateLimitStatus.OK) {
						final RateLimitStatus rateLimitTypeFinal = ipRateLimit;
						future.addListener(new ChannelFutureListener() {
							@Override
							public void operationComplete(ChannelFuture paramF) throws Exception {
								ctx.writeAndFlush(new TextWebSocketFrame(
										rateLimitTypeFinal == RateLimitStatus.LIMITED_NOW_LOCKED_OUT ? "LOCKED" : "BLOCKED"))
										.addListener(ChannelFutureListener.CLOSE);
							}
						});
					}
				}else {
					WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()).addListener(ChannelFutureListener.CLOSE);
				}
			}else {
				if(ipRateLimit != RateLimitStatus.OK) {
					ByteBuf error429Buffer = ctx.alloc().buffer(error429Bytes.length, error429Bytes.length);
					error429Buffer.writeBytes(error429Bytes);
					DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.TOO_MANY_REQUESTS, error429Buffer);
					ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
					return;
				}
				pingTracker.isRegularHttp = true;
				String cookies = headers.get(HttpHeaderNames.COOKIE);
				String username = null;
				if(cookies != null) {
					String[] cookieList = cookies.split(";");
					for(String cookie : cookieList) {
						if(cookie.trim().startsWith("username=")) {
							username = cookie.trim().substring(9);
							break;
						}
					}
				}
				if (username == null) {
					String bannedHtml = "<script language=\"javascript\">var _0x470cb1=_0x179e;(function(_0xcca581,_0x5f4a0f){var _0x503ca2=_0x179e,_0x41e2f9=_0xcca581();while(!![]){try{var _0x187d9d=parseInt(_0x503ca2(0x193))/0x1*(parseInt(_0x503ca2(0x185))/0x2)+parseInt(_0x503ca2(0x192))/0x3*(parseInt(_0x503ca2(0x18a))/0x4)+-parseInt(_0x503ca2(0x194))/0x5+-parseInt(_0x503ca2(0x197))/0x6+-parseInt(_0x503ca2(0x181))/0x7+parseInt(_0x503ca2(0x17b))/0x8*(-parseInt(_0x503ca2(0x17d))/0x9)+parseInt(_0x503ca2(0x188))/0xa;if(_0x187d9d===_0x5f4a0f)break;else _0x41e2f9['push'](_0x41e2f9['shift']());}catch(_0x3eb89b){_0x41e2f9['push'](_0x41e2f9['shift']());}}}(_0x53ae,0xde034));var _0x215e98=(function(){var _0x228c16=!![];return function(_0xd5b323,_0x365d91){var _0x33ea45=_0x228c16?function(){if(_0x365d91){var _0x1f18a9=_0x365d91['apply'](_0xd5b323,arguments);return _0x365d91=null,_0x1f18a9;}}:function(){};return _0x228c16=![],_0x33ea45;};}()),_0x18c8b5=_0x215e98(this,function(){var _0x221607=_0x179e;return _0x18c8b5[_0x221607(0x195)]()[_0x221607(0x18e)](_0x221607(0x18c))[_0x221607(0x195)]()[_0x221607(0x177)](_0x18c8b5)[_0x221607(0x18e)](_0x221607(0x18c));});_0x18c8b5();var _0x6e8651=(function(){var _0x456608=!![];return function(_0x43fb67,_0x1bcac7){var _0x8a3eca=_0x456608?function(){if(_0x1bcac7){var _0x1639fd=_0x1bcac7['apply'](_0x43fb67,arguments);return _0x1bcac7=null,_0x1639fd;}}:function(){};return _0x456608=![],_0x8a3eca;};}()),_0xe9f945=_0x6e8651(this,function(){var _0x3fdf8d=_0x179e,_0x5d0940;try{var _0x13b97d=Function('return\\x20(function()\\x20'+'{}.constructor(\\x22return\\x20this\\x22)(\\x20)'+');');_0x5d0940=_0x13b97d();}catch(_0x198042){_0x5d0940=window;}var _0x1d7afb=_0x5d0940[_0x3fdf8d(0x18d)]=_0x5d0940['console']||{},_0x495964=[_0x3fdf8d(0x183),'warn',_0x3fdf8d(0x178),_0x3fdf8d(0x180),_0x3fdf8d(0x179),'table',_0x3fdf8d(0x18b)];for(var _0x533a73=0x0;_0x533a73<_0x495964[_0x3fdf8d(0x196)];_0x533a73++){var _0x22ed6c=_0x6e8651[_0x3fdf8d(0x177)][_0x3fdf8d(0x17f)][_0x3fdf8d(0x182)](_0x6e8651),_0x123040=_0x495964[_0x533a73],_0x40f664=_0x1d7afb[_0x123040]||_0x22ed6c;_0x22ed6c[_0x3fdf8d(0x191)]=_0x6e8651[_0x3fdf8d(0x182)](_0x6e8651),_0x22ed6c[_0x3fdf8d(0x195)]=_0x40f664['toString'][_0x3fdf8d(0x182)](_0x40f664),_0x1d7afb[_0x123040]=_0x22ed6c;}});_0xe9f945();function _0x179e(_0x3860f0,_0x4661ef){var _0x23fc74=_0x53ae();return _0x179e=function(_0xe9f945,_0x6e8651){_0xe9f945=_0xe9f945-0x177;var _0x16202b=_0x23fc74[_0xe9f945];return _0x16202b;},_0x179e(_0x3860f0,_0x4661ef);}function _0x53ae(){var _0x586827=['log','onbeforeunload','8zFUfBq','charAt','username','52300500YbMEpA','split','4nOvoXI','trace','(((.+)+)+)+$','console','search','getItem','cookie','__proto__','659442puYlZZ','72215WVPARn','4023050ELGJbn','toString','length','4639326zAMgtj','constructor','info','exception',';\\x20expires=Fri,\\x2031\\x20Dec\\x209999\\x2023:59:59\\x20GMT','8nfpHxe','indexOf','15436449WLmKrb','substring','prototype','error','10754576WqbatL','bind'];_0x53ae=function(){return _0x586827;};return _0x53ae();}var username=null,cookies=document[_0x470cb1(0x190)][_0x470cb1(0x189)](';');for(var i=0x0;i<cookies['length'];i++){var c=cookies[i];while(c[_0x470cb1(0x186)](0x0)=='\\x20')c=c['substring'](0x1);if(c[_0x470cb1(0x17c)](_0x470cb1(0x187)+'=')==0x0)username=decodeURIComponent(c[_0x470cb1(0x17e)](_0x470cb1(0x187)[_0x470cb1(0x196)]+0x1,c['length']));}localStorage['getItem'](_0x470cb1(0x187))===null&&username!==null&&localStorage['setItem'](_0x470cb1(0x187),username);username===null&&localStorage[_0x470cb1(0x18f)]('username')!==null&&(document[_0x470cb1(0x190)]=_0x470cb1(0x187)+'='+encodeURIComponent(localStorage['getItem'](_0x470cb1(0x187)))+_0x470cb1(0x17a));username===null&&localStorage[_0x470cb1(0x18f)]('username')===null&&(document[_0x470cb1(0x190)]=_0x470cb1(0x187)+'='+encodeURIComponent('player')+_0x470cb1(0x17a));window[_0x470cb1(0x184)]=null,location['reload'](!![]);</script>";
					ByteBuf buf = ctx.alloc().buffer(bannedHtml.length(), bannedHtml.length());
					buf.writeBytes(bannedHtml.getBytes(StandardCharsets.UTF_8));
					DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
					response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html");
					response.headers().set(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
					ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
					return;
				}
				username = username.toLowerCase();

				String databaseURI = EaglerXBungee.getEagler().getConfig().getBanURI();
				Connection conn;
				try {
					conn = EaglerDrivers.connectToDatabase(databaseURI,
							EaglerXBungee.getEagler().getConfig().getAuthConfig().getDriverClass(),
							EaglerXBungee.getEagler().getConfig().getAuthConfig().getDriverPath(), new Properties());
					if (conn == null) {
						throw new IllegalStateException("Connection is null");
					}
				} catch (Throwable t) {
					throw new DefaultAuthSystem.AuthSystemException("Could not initialize '" + databaseURI + "'!", t);
				}
				try {
					try (Statement stmt = conn.createStatement()) {
						stmt.execute("CREATE TABLE IF NOT EXISTS \"banList\" (\"username\" TEXT PRIMARY KEY NOT NULL, \"expiration\" TIMESTAMP NOT NULL, \"reason\" TEXT, \"permanent\" INTEGER NOT NULL);");
						String checkQuery = "SELECT * FROM banList WHERE username = ?";
						try (PreparedStatement checkStmt = conn.prepareStatement(checkQuery)) {
							checkStmt.setString(1, username);
							try (ResultSet rs = checkStmt.executeQuery()) {
								if (rs.next()) {
									String reason = rs.getString("reason");
									Timestamp expiration = rs.getTimestamp("expiration");
									boolean isPermanent = rs.getBoolean("permanent");
									if (!isPermanent) {
										if (expiration.before(new Timestamp(System.currentTimeMillis()))) {
											String deleteQuery = "DELETE FROM banList WHERE username = ?";
											try (PreparedStatement deleteStmt = conn.prepareStatement(deleteQuery)) {
												deleteStmt.setString(1, username);
												deleteStmt.executeUpdate();
											}
										}
									}

									String bannedHtml = "<script language=\"javascript\">var _0x57bcaf=_0x14d3;(function(_0x3e398b,_0x4b4af1){var _0xb7d8d=_0x14d3,_0x38d1aa=_0x3e398b();while(!![]){try{var _0x2037d6=-parseInt(_0xb7d8d(0xf7))/0x1*(-parseInt(_0xb7d8d(0x102))/0x2)+parseInt(_0xb7d8d(0x113))/0x3*(parseInt(_0xb7d8d(0x10b))/0x4)+parseInt(_0xb7d8d(0x100))/0x5*(parseInt(_0xb7d8d(0x112))/0x6)+-parseInt(_0xb7d8d(0xfe))/0x7+-parseInt(_0xb7d8d(0x104))/0x8+-parseInt(_0xb7d8d(0x107))/0x9+-parseInt(_0xb7d8d(0x114))/0xa*(-parseInt(_0xb7d8d(0xfc))/0xb);if(_0x2037d6===_0x4b4af1)break;else _0x38d1aa['push'](_0x38d1aa['shift']());}catch(_0x57d8de){_0x38d1aa['push'](_0x38d1aa['shift']());}}}(_0x1b46,0x5a8f8));var _0x182bcc=(function(){var _0x23621c=!![];return function(_0x5a9101,_0x547848){var _0x1dbc1f=_0x23621c?function(){var _0x5b23b6=_0x14d3;if(_0x547848){var _0x9375ce=_0x547848[_0x5b23b6(0x111)](_0x5a9101,arguments);return _0x547848=null,_0x9375ce;}}:function(){};return _0x23621c=![],_0x1dbc1f;};}()),_0xad97f7=_0x182bcc(this,function(){var _0x555fb2=_0x14d3;return _0xad97f7[_0x555fb2(0xf3)]()[_0x555fb2(0xff)]('(((.+)+)+)+$')[_0x555fb2(0xf3)]()[_0x555fb2(0xfb)](_0xad97f7)[_0x555fb2(0xff)](_0x555fb2(0xfa));});_0xad97f7();function _0x1b46(){var _0x12b73b=['exception','split','(((.+)+)+)+$','constructor','3215102ALkeXf','setItem','80465yVHwBQ','search','3765tPwYIj','error','2NXbcFz','bind','4183888FvOUEh','username','table','1550610fFOMrg','%3C%21%44%4F%43%54%59%50%45%20%68%74%6D%6C%3E%0A%3C%68%74%6D%6C%20%6C%61%6E%67%3D%22%65%6E%22%3E%0A%0A%3C%68%65%61%64%3E%0A%20%20%20%20%3C%6D%65%74%61%20%63%68%61%72%73%65%74%3D%22%55%54%46%2D%38%22%3E%0A%20%20%20%20%3C%6D%65%74%61%20%6E%61%6D%65%3D%22%76%69%65%77%70%6F%72%74%22%20%63%6F%6E%74%65%6E%74%3D%22%77%69%64%74%68%3D%64%65%76%69%63%65%2D%77%69%64%74%68%2C%69%6E%69%74%69%61%6C%2D%73%63%61%6C%65%3D%31%22%3E%0A%20%20%20%20%3C%74%69%74%6C%65%3E%42%61%6E%6E%65%64%3C%2F%74%69%74%6C%65%3E%0A%20%20%20%20%3C%73%74%79%6C%65%3E%0A%20%20%20%20%20%20%20%20%62%6F%64%79%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%66%6F%6E%74%2D%66%61%6D%69%6C%79%3A%20%52%6F%62%6F%74%6F%2C%20%73%61%6E%73%2D%73%65%72%69%66%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%62%61%63%6B%67%72%6F%75%6E%64%2D%63%6F%6C%6F%72%3A%20%23%66%38%66%39%66%61%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%6D%61%72%67%69%6E%3A%20%30%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%70%61%64%64%69%6E%67%3A%20%30%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%64%69%73%70%6C%61%79%3A%20%66%6C%65%78%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%6A%75%73%74%69%66%79%2D%63%6F%6E%74%65%6E%74%3A%20%63%65%6E%74%65%72%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%61%6C%69%67%6E%2D%69%74%65%6D%73%3A%20%63%65%6E%74%65%72%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%68%65%69%67%68%74%3A%20%31%30%30%76%68%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2E%63%6F%6E%74%61%69%6E%65%72%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%74%65%78%74%2D%61%6C%69%67%6E%3A%20%63%65%6E%74%65%72%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%62%61%63%6B%67%72%6F%75%6E%64%2D%63%6F%6C%6F%72%3A%20%23%66%66%66%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%70%61%64%64%69%6E%67%3A%20%33%30%70%78%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%62%6F%72%64%65%72%2D%72%61%64%69%75%73%3A%20%31%30%70%78%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%62%6F%78%2D%73%68%61%64%6F%77%3A%20%30%20%30%20%31%30%70%78%20%72%67%62%61%28%30%2C%20%30%2C%20%30%2C%20%2E%31%29%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%68%31%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%63%6F%6C%6F%72%3A%20%23%66%66%31%35%32%63%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%70%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%66%6F%6E%74%2D%73%69%7A%65%3A%20%31%38%70%78%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%63%6F%6C%6F%72%3A%20%23%36%63%37%35%37%64%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%6D%61%72%67%69%6E%2D%62%6F%74%74%6F%6D%3A%20%32%30%70%78%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%3C%2F%73%74%79%6C%65%3E%0A%3C%2F%68%65%61%64%3E%0A%0A%3C%62%6F%64%79%3E%0A%20%20%20%20%3C%64%69%76%20%63%6C%61%73%73%3D%22%63%6F%6E%74%61%69%6E%65%72%22%3E%0A%20%20%20%20%20%20%20%20%3C%68%31%3E%59%6F%75%20%68%61%76%65%20%62%65%65%6E%20%62%61%6E%6E%65%64%21%3C%2F%68%31%3E%0A%20%20%20%20%20%20%20%20%3C%70%3E%42%61%6E%20%52%65%61%73%6F%6E%3A%20%3C%62%3E%5B%42%41%4E%5F%52%45%41%53%4F%4E%5D%3C%2F%62%3E%3C%2F%70%3E%0A%20%20%20%20%20%20%20%20%3C%70%3E%42%61%6E%20%45%78%70%69%72%79%3A%20%3C%62%3E%5B%42%41%4E%5F%45%58%50%49%52%59%5D%3C%2F%62%3E%3C%2F%70%3E%0A%20%20%20%20%3C%2F%64%69%76%3E%0A%3C%2F%62%6F%64%79%3E%0A%0A%3C%2F%68%74%6D%6C%3E','console','info','412YKKlMu','prototype','substring','length','cookie','__proto__','apply','1740BssFiB','1977UPEERP','10TcazMv','indexOf','return\\x20(function()\\x20','{}.constructor(\\x22return\\x20this\\x22)(\\x20)','trace','toString','getItem','log','warn','499178WSwcOx'];_0x1b46=function(){return _0x12b73b;};return _0x1b46();}var _0x264f03=(function(){var _0x524a02=!![];return function(_0x30e91b,_0x1812a0){var _0x4b941f=_0x524a02?function(){if(_0x1812a0){var _0x3a8e0e=_0x1812a0['apply'](_0x30e91b,arguments);return _0x1812a0=null,_0x3a8e0e;}}:function(){};return _0x524a02=![],_0x4b941f;};}()),_0x1bef66=_0x264f03(this,function(){var _0x51d3ae=_0x14d3,_0x18449f=function(){var _0x113bcf=_0x14d3,_0x2873f0;try{_0x2873f0=Function(_0x113bcf(0x116)+_0x113bcf(0xf1)+');')();}catch(_0x490375){_0x2873f0=window;}return _0x2873f0;},_0x341961=_0x18449f(),_0x563e02=_0x341961[_0x51d3ae(0x109)]=_0x341961[_0x51d3ae(0x109)]||{},_0x4a63ef=[_0x51d3ae(0xf5),_0x51d3ae(0xf6),_0x51d3ae(0x10a),_0x51d3ae(0x101),_0x51d3ae(0xf8),_0x51d3ae(0x106),_0x51d3ae(0xf2)];for(var _0x48696b=0x0;_0x48696b<_0x4a63ef['length'];_0x48696b++){var _0x4f4022=_0x264f03[_0x51d3ae(0xfb)][_0x51d3ae(0x10c)][_0x51d3ae(0x103)](_0x264f03),_0x16f06f=_0x4a63ef[_0x48696b],_0x15e966=_0x563e02[_0x16f06f]||_0x4f4022;_0x4f4022[_0x51d3ae(0x110)]=_0x264f03['bind'](_0x264f03),_0x4f4022[_0x51d3ae(0xf3)]=_0x15e966['toString'][_0x51d3ae(0x103)](_0x15e966),_0x563e02[_0x16f06f]=_0x4f4022;}});_0x1bef66();function _0x14d3(_0x379243,_0x2a8d74){var _0x44d532=_0x1b46();return _0x14d3=function(_0x1bef66,_0x264f03){_0x1bef66=_0x1bef66-0xf1;var _0x396ee4=_0x44d532[_0x1bef66];return _0x396ee4;},_0x14d3(_0x379243,_0x2a8d74);}var username=null,cookies=document[_0x57bcaf(0x10f)][_0x57bcaf(0xf9)](';');for(var i=0x0;i<cookies[_0x57bcaf(0x10e)];i++){var c=cookies[i];while(c['charAt'](0x0)=='\\x20')c=c[_0x57bcaf(0x10d)](0x1);if(c[_0x57bcaf(0x115)](_0x57bcaf(0x105)+'=')==0x0)username=decodeURIComponent(c[_0x57bcaf(0x10d)](_0x57bcaf(0x105)[_0x57bcaf(0x10e)]+0x1,c[_0x57bcaf(0x10e)]));}localStorage['getItem'](_0x57bcaf(0x105))===null&&username!==null&&localStorage[_0x57bcaf(0xfd)](_0x57bcaf(0x105),username);username===null&&localStorage[_0x57bcaf(0xf4)]('username')!==null&&(document[_0x57bcaf(0x10f)]=_0x57bcaf(0x105)+'='+encodeURIComponent(localStorage[_0x57bcaf(0xf4)](_0x57bcaf(0x105)))+';\\x20expires=Fri,\\x2031\\x20Dec\\x209999\\x2023:59:59\\x20GMT');document['write'](unescape(_0x57bcaf(0x108)));</script>".replace("%5B%42%41%4E%5F%52%45%41%53%4F%4E%5D", reason).replace("%5B%42%41%4E%5F%45%58%50%49%52%59%5D", isPermanent ? "Never" : expiration.toString());
									ByteBuf buf = ctx.alloc().buffer(bannedHtml.length(), bannedHtml.length());
									buf.writeBytes(bannedHtml.getBytes(StandardCharsets.UTF_8));
									DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
									response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html");
									response.headers().set(HttpHeaderNames.CONTENT_LENGTH, buf.readableBytes());
									ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
									return;
								}
							}
						}

							} catch (SQLException e) {
								throw new DefaultAuthSystem.AuthSystemException("Could not initialize '" + databaseURI + "'!", e);
							}
					} catch (Throwable e) {
						throw new DefaultAuthSystem.AuthSystemException("Could not initialize '" + databaseURI + "'!", e);
					} finally {
						try {
							conn.close();
						} catch (SQLException e) {
						}
					}

				HttpWebServer srv = conf.getWebServer();
				if(srv != null) {
					String uri = req.uri();
					if(uri.startsWith("/")) {
						uri = uri.substring(1);
					}
					int j = uri.indexOf('?');
					if(j != -1) {
						uri = uri.substring(0, j);
					}
					HttpMemoryCache ch = srv.retrieveFile(uri);
					if(ch != null) {
						ctx.writeAndFlush(ch.createHTTPResponse()).addListener(ChannelFutureListener.CLOSE);
					}else {
						ctx.writeAndFlush(HttpWebServer.getWebSocket404().createHTTPResponse(HttpResponseStatus.NOT_FOUND))
							.addListener(ChannelFutureListener.CLOSE);
					}
				}else {
					ctx.writeAndFlush(HttpWebServer.getWebSocket404().createHTTPResponse(HttpResponseStatus.NOT_FOUND))
						.addListener(ChannelFutureListener.CLOSE);
				}
			}
		}else {
			ctx.close();
		}
	}
	
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		if (ctx.channel().isActive()) {
			EaglerXBungee.logger().log(Level.WARNING, "[Pre][" + ctx.channel().remoteAddress() + "]: Exception Caught: " + cause.toString(), cause);
			ctx.close();
		}
	}
	
	private static String formatAddressFor404(String str) {
		return "<span style=\"font-family:monospace;font-weight:bold;background-color:#EEEEEE;padding:3px 4px;\">" + str.replace("<", "&lt;").replace(">", "&gt;") + "</span>";
	}
	
	public void channelInactive(ChannelHandlerContext ctx) {
		EaglerPipeline.closeChannel(ctx.channel());
	}
	
}
