/* 
    This file is a part of the SteamWar software.
    
    Copyright (C) 2020  SteamWar.de-Serverteam

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package de.steamwar.core;

import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.command.*;
import de.steamwar.core.authlib.AuthlibInjector;
import de.steamwar.core.events.*;
import de.steamwar.message.Message;
import de.steamwar.network.NetworkReceiver;
import de.steamwar.network.handlers.ServerDataHandler;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.internal.Statement;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.logging.Level;

public class Core extends JavaPlugin{

	public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader());

	private static final int VERSION = Integer.parseInt(Bukkit.getServer().getClass().getPackage().getName().split("_", 3)[1]);

	public static int getVersion(){
		return VERSION;
	}

	private static JavaPlugin instance;
	public static JavaPlugin getInstance() {
		return instance;
	}
	public static void setInstance(JavaPlugin instance) {
		Core.instance = instance;
	}

	private ErrorHandler errorHandler;
	private CrashDetector crashDetector;

	@Override
	public void onLoad() {
		setInstance(this);
	}
	
	@Override
	public void onEnable() {
		errorHandler = new ErrorHandler();
		crashDetector = new CrashDetector();

		SWCommandUtils.init((SWTypeMapperCreator<TypeMapper<Object>, CommandSender, Object>) (mapper, tabCompleter) -> new TypeMapper<Object>() {
			@Override
			public Object map(CommandSender commandSender, String[] previousArguments, String s) {
				return mapper.apply(s);
			}

			@Override
			public Collection<String> tabCompletes(CommandSender sender, String[] previousArguments, String s) {
				return tabCompleter.apply(sender, s);
			}
		});

		for(Listener listener : new Listener[]{new CaseInsensitiveCommandsListener(), new PlayerJoinedEvent(), new ChattingEvent(), new WorldLoadEvent(), RecipeDiscoverWrapper.impl}) {
			getServer().getPluginManager().registerEvents(listener, this);
		}
		if(!Statement.productionDatabase()) {
			getServer().getPluginManager().registerEvents(LocaleChangeWrapper.impl, this);
		}

		getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver());
		getServer().getMessenger().registerOutgoingPluginChannel(this, "sw:bridge");

		if(Core.getVersion() < 19)
			AuthlibInjector.inject();

		TinyProtocol.init();
		CheckpointUtils.signalHandler();
		new AntiNocom();

		if(Core.getVersion() < 17 && Bukkit.getPluginManager().getPlugin("ViaVersion") != null)
			new PartialChunkFixer();

		if(Core.getVersion() >= 19)
			new ServerDataHandler();

		Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20);
		Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SteamwarUser::clear, 72000, 72000);
		Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SchematicNode::clear, 20L * 30, 20L * 30);

		try {
			getLogger().log(Level.INFO, "Running on: " + new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream())).readLine());
		} catch (IOException e) {
			throw new SecurityException("Could not load Hostname", e);
		}
	}

	@Override
	public void onDisable() {
		TinyProtocol.instance.close();
		errorHandler.unregister();
		if(crashDetector.onMainThread())
			Statement.closeAll();
	}
}
