/*
 * Copyright (c) jbs and others.
 * Visit the jbs website for more information.
 * @date 23-7-2017
 * @author dirkdev
 */

package jbs;

import jbs.middleware.IMiddleware;
import jbs.routers.BasisRouter;
import jbs.routers.IRouter;
import jbs.routers.RouteHandler;
import jbs.sockets.Server;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class Jbs
{
	private BasisRouter                                                   basisRouter;
	private List<IMiddleware>                                             middlewares;
	private Map<String, Map<HttpMethod, Class<? extends RouteHandler>[]>> routes;
	private HashMap<HttpMethod, Class<? extends RouteHandler>[]>          defaultHandlers;

	public Jbs()
	{
		this.basisRouter = new BasisRouter("");
		this.middlewares = new LinkedList<>();
		this.routes = new HashMap<>();
		this.defaultHandlers = null;
	}

	/**
	 * Register this middleware
	 *
	 * @param middleware
	 */
	public void use(IMiddleware middleware)
	{
		this.middlewares.add(middleware);
	}

	/**
	 * Mounts the provided router on the server
	 *
	 * @param router
	 */
	public void use(IRouter router)
	{
		this.basisRouter.mount(router);
	}


	/**
	 * Creates a default route for all httpMethods
	 *
	 * @param routeHandler
	 */
	public void setDefault(Class<? extends RouteHandler> routeHandler)
	{
		this.defaultHandlers = new HashMap<>();
		this.defaultHandlers.put(HttpMethod.GET, new Class[]{routeHandler});
		this.defaultHandlers.put(HttpMethod.POST, new Class[]{routeHandler});
		this.defaultHandlers.put(HttpMethod.PUT, new Class[]{routeHandler});
		this.defaultHandlers.put(HttpMethod.DELETE, new Class[]{routeHandler});
	}

	/**
	 * @param port
	 * @see Jbs#normalizeRoutes()
	 * @see Server
	 * Starts a new server in a new thread
	 */
	public void listen(int port, int threadCount)
	{
		this.normalizeRoutes();
		Server server = new Server(port, threadCount, this.routes, this.middlewares);
		new Thread(server).start();
	}

	/**
	 * Replaces * with regex for any character from A-Za-Z0-9
	 * Replaces ** with regex for any character from A-Za-Z0-9-_/.
	 * Will also put the defaultHandler at the end of the routes
	 */
	private void normalizeRoutes()
	{
		Map<String, Map<HttpMethod, Class<? extends RouteHandler>[]>> allRoutes = this.basisRouter.getRoutes();
		for (Entry<String, Map<HttpMethod, Class<? extends RouteHandler>[]>> entry : allRoutes.entrySet())
		{
			String route = this.basisRouter.getMountPoint() + entry.getKey().replace("**", "[-\\w+_/]+").replace("*", "\\w+");
			this.routes.put(route, entry.getValue());
		}

		if (this.defaultHandlers != null)
			this.routes.put("[-\\w+_/.]+", this.defaultHandlers);
	}

}
