/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pw.yumc.Residence.economy.rent;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;

import com.bekvon.bukkit.residence.event.ResidenceRentEvent;
import com.bekvon.bukkit.residence.event.ResidenceRentEvent.RentEventType;
import com.bekvon.bukkit.residence.permissions.PermissionGroup;
import com.bekvon.bukkit.residence.protection.ClaimedResidence;
import com.bekvon.bukkit.residence.protection.FlagPermissions.FlagState;

import pw.yumc.Residence.ResidenceMain;

/**
 *
 * @author Administrator
 */
public class RentManager {
    protected ResidenceMain plugin;
    protected PluginManager pm;
    protected Map<String, RentableLand> rentableLand;
    protected Map<String, RentedLand> rentedLand;

    public RentManager(final ResidenceMain plugin) {
        this.plugin = plugin;
        pm = plugin.getServer().getPluginManager();
        rentedLand = new HashMap<String, RentedLand>();
        rentableLand = new HashMap<String, RentableLand>();
    }

    @SuppressWarnings("unchecked")
    public static RentManager load(final ResidenceMain plugin, final Map<String, Object> root) {
        final RentManager rentManager = new RentManager(plugin);
        if (root != null) {
            final Map<String, Object> rentables = (Map<String, Object>) root.get("Rentables");
            for (final Entry<String, Object> rent : rentables.entrySet()) {
                rentManager.rentableLand.put(rent.getKey(), RentableLand.load((Map<String, Object>) rent.getValue()));
            }
            final Map<String, Object> rented = (Map<String, Object>) root.get("Rented");
            for (final Entry<String, Object> rent : rented.entrySet()) {
                rentManager.rentedLand.put(rent.getKey(), RentedLand.load((Map<String, Object>) rent.getValue()));
            }
        }
        return rentManager;
    }

    public void checkCurrentRents() {
        final Iterator<Entry<String, RentedLand>> it = rentedLand.entrySet().iterator();
        while (it.hasNext()) {
            final Entry<String, RentedLand> next = it.next();
            final RentedLand land = next.getValue();
            if (land.endTime <= System.currentTimeMillis()) {
                final ClaimedResidence res = plugin.getResidenceManager().getByName(next.getKey());
                if (plugin.getConfigManager().debugEnabled()) {
                    System.out.println("Rent Check: " + next.getKey());
                }
                if (res != null) {
                    final ResidenceRentEvent revent = new ResidenceRentEvent(res, null, RentEventType.RENT_EXPIRE);
                    pm.callEvent(revent);
                    if (!revent.isCancelled()) {
                        final RentableLand rentable = rentableLand.get(next.getKey());
                        if (!rentable.repeatable) {
                            rentableLand.remove(next.getKey());
                            it.remove();
                            res.getPermissions().applyDefaultFlags();
                        } else if (land.autoRefresh) {
                            if (!plugin.getEconomyManager().canAfford(land.player, rentable.cost)) {
                                it.remove();
                                res.getPermissions().applyDefaultFlags();
                            } else if (!plugin.getEconomyManager().transfer(land.player, res.getPermissions().getOwner(), rentable.cost)) {
                                it.remove();
                                res.getPermissions().applyDefaultFlags();
                            } else {
                                land.endTime = System.currentTimeMillis() + this.daysToMs(rentable.days);
                            }
                        } else {
                            res.getPermissions().applyDefaultFlags();
                            it.remove();
                        }
                    }
                } else {
                    rentableLand.remove(next.getKey());
                    it.remove();
                }
            }
        }
    }

    public int getCostOfRent(final String landName) {
        return rentableLand.containsKey(landName) ? rentableLand.get(landName).cost : 0;
    }

    public int getRentableCount(final String player) {
        final Set<String> set = rentableLand.keySet();
        int count = 0;
        for (final String land : set) {
            final ClaimedResidence res = plugin.getResidenceManager().getByName(land);
            if (res != null) {
                if (res.getPermissions().getOwner().equalsIgnoreCase(player)) {
                    count++;
                }
            }
        }
        return count;
    }

    public boolean getRentableRepeatable(final String landName) {
        return rentableLand.containsKey(landName) ? rentableLand.get(landName).repeatable : false;
    }

    public int getRentCount(final String player) {
        final Set<Entry<String, RentedLand>> set = rentedLand.entrySet();
        int count = 0;
        for (final Entry<String, RentedLand> land : set) {
            if (land.getValue().player.equalsIgnoreCase(player)) {
                count++;
            }
        }
        return count;
    }

    public int getRentDays(final String landName) {
        return rentableLand.containsKey(landName) ? rentableLand.get(landName).days : 0;
    }

    public boolean getRentedAutoRepeats(final String landName) {
        return getRentableRepeatable(landName) ? (rentedLand.containsKey(landName) ? rentedLand.get(landName).autoRefresh : false) : false;
    }

    public String getRentingPlayer(final String landName) {
        return rentedLand.containsKey(landName) ? rentedLand.get(landName).player : null;
    }

    public boolean isForRent(final String landName) {
        return rentableLand.containsKey(landName);
    }

    public boolean isRented(final String landName) {
        return rentedLand.containsKey(landName);
    }

    public void printRentableResidences(final Player player) {
        final Set<Entry<String, RentableLand>> set = rentableLand.entrySet();
        player.sendMessage(ChatColor.YELLOW + plugin.getLanguage().getPhrase("RentableLand") + ":");
        final StringBuilder sbuild = new StringBuilder();
        sbuild.append(ChatColor.GREEN);
        boolean firstadd = true;
        for (final Entry<String, RentableLand> land : set) {
            if (!this.isRented(land.getKey())) {
                if (!firstadd) {
                    sbuild.append(", ");
                } else {
                    firstadd = false;
                }
                sbuild.append(land.getKey());
            }
        }
        player.sendMessage(sbuild.toString());
    }

    public void printRentInfo(final Player player, final String landName) {
        final RentableLand rentable = rentableLand.get(landName);
        final RentedLand rented = rentedLand.get(landName);
        if (rentable != null) {
            player.sendMessage(ChatColor.GOLD + plugin.getLanguage().getPhrase("Land") + ":" + ChatColor.DARK_GREEN + landName);
            player.sendMessage(ChatColor.YELLOW + plugin.getLanguage().getPhrase("Cost") + ": " + ChatColor.DARK_AQUA + rentable.cost + " per " + rentable.days + " days");
            player.sendMessage(ChatColor.GREEN + plugin.getLanguage().getPhrase("RentableAutoRenew") + ":" + ChatColor.DARK_AQUA + rentable.repeatable);
            if (rented != null) {
                player.sendMessage(ChatColor.GOLD + plugin.getLanguage().getPhrase("Status") + ":" + ChatColor.YELLOW + " "
                        + plugin.getLanguage().getPhrase("ResidenceRentedBy", ChatColor.RED + rented.player + ChatColor.YELLOW));
                player.sendMessage(ChatColor.YELLOW + plugin.getLanguage().getPhrase("RentExpire") + ":" + ChatColor.GREEN + new Date(rented.endTime));
                player.sendMessage(ChatColor.GREEN + plugin.getLanguage().getPhrase("RentAutoRenew") + ":" + ChatColor.DARK_AQUA + rented.autoRefresh);
            } else {
                player.sendMessage(ChatColor.GOLD + plugin.getLanguage().getPhrase("Status") + ":" + ChatColor.GREEN + " " + plugin.getLanguage().getPhrase("Available"));
            }
        } else {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceNotForRent"));
        }
    }

    public void removeFromForRent(final Player player, final String landName, final boolean resadmin) {
        final RentedLand rent = rentedLand.get(landName);
        if (rent == null) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceNotRented"));
            return;
        }
        if (resadmin || rent.player.equalsIgnoreCase(player.getName())) {
            final ResidenceRentEvent revent = new ResidenceRentEvent(plugin.getResidenceManager().getByName(landName), player, RentEventType.UNRENTABLE);
            pm.callEvent(revent);
            if (revent.isCancelled()) {
                return;
            }
            rentedLand.remove(landName);
            if (!rentableLand.get(landName).repeatable) {
                rentableLand.remove(landName);
            }
            final ClaimedResidence res = plugin.getResidenceManager().getByName(landName);
            if (res != null) {
                res.getPermissions().applyDefaultFlags();
            }
            player.sendMessage(ChatColor.GREEN + plugin.getLanguage().getPhrase("ResidenceUnrent", ChatColor.YELLOW + landName + ChatColor.GREEN));
        } else {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("NoPermission"));
        }
    }

    public void removeFromRent(final String landName) {
        rentedLand.remove(landName);
    }

    public void removeRentable(final String landName) {
        removeFromRent(landName);
        rentableLand.remove(landName);
    }

    public void rent(final Player player, final String landName, final boolean repeat, final boolean resadmin) {
        if (!plugin.getConfigManager().enabledRentSystem()) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("RentDisabled"));
            return;
        }
        final ClaimedResidence res = plugin.getResidenceManager().getByName(landName);
        if (res != null) {
            if (res.getPermissions().getOwner().equalsIgnoreCase(player.getName())) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("OwnerRentFail"));
                return;
            }
        } else {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("InvalidResidence"));
            return;
        }
        final PermissionGroup group = plugin.getPermissionManager().getGroup(player);
        if (!resadmin && this.getRentCount(player.getName()) >= group.getMaxRents()) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceMaxRent"));
            return;
        }
        if (!this.isForRent(landName)) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceNotForRent"));
            return;
        }
        if (this.isRented(landName)) {
            final String[] split = landName.split("\\.");
            if (split.length != 0) {
                player.sendMessage(plugin.getLanguage().getPhrase("ResidenceAlreadyRented",
                        ChatColor.YELLOW + split[split.length - 1] + ChatColor.RED + "." + ChatColor.YELLOW + this.getRentingPlayer(landName)));
            }
            return;
        }
        final RentableLand land = rentableLand.get(landName);
        if (plugin.getEconomyManager().canAfford(player.getName(), land.cost)) {
            final ResidenceRentEvent revent = new ResidenceRentEvent(res, player, RentEventType.RENT);
            pm.callEvent(revent);
            if (revent.isCancelled()) {
                return;
            }
            if (plugin.getEconomyManager().transfer(player.getName(), res.getPermissions().getOwner(), land.cost)) {
                final RentedLand newrent = new RentedLand();
                newrent.player = player.getName();
                newrent.startTime = System.currentTimeMillis();
                newrent.endTime = System.currentTimeMillis() + daysToMs(land.days);
                newrent.autoRefresh = repeat;
                rentedLand.put(landName, newrent);
                res.getPermissions().copyUserPermissions(res.getPermissions().getOwner(), player.getName());
                res.getPermissions().clearPlayersFlags(res.getPermissions().getOwner());
                res.getPermissions().setPlayerFlag(player.getName(), "admin", FlagState.TRUE);
                final String[] split = landName.split("\\.");
                if (split.length != 0) {
                    player.sendMessage(ChatColor.GREEN + plugin.getLanguage().getPhrase("ResidenceRentSuccess",
                            ChatColor.YELLOW + split[split.length - 1] + ChatColor.GREEN + "." + ChatColor.YELLOW + land.days + ChatColor.GREEN));
                }
            } else {
                player.sendMessage(ChatColor.RED + "Error, unable to transfer money...");
            }
        } else {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("NotEnoughMoney"));
        }
    }

    public Map<String, Object> save() {
        final Map<String, Object> root = new HashMap<String, Object>();
        final Map<String, Object> rentables = new HashMap<String, Object>();
        for (final Entry<String, RentableLand> rent : rentableLand.entrySet()) {
            rentables.put(rent.getKey(), rent.getValue().save());
        }
        final Map<String, Object> rented = new HashMap<String, Object>();
        for (final Entry<String, RentedLand> rent : rentedLand.entrySet()) {
            rented.put(rent.getKey(), rent.getValue().save());
        }
        root.put("Rentables", rentables);
        root.put("Rented", rented);
        return root;
    }

    public void setForRent(final Player player, final String landName, final int amount, final int days, final boolean repeatable, final boolean resadmin) {
        if (!plugin.getConfigManager().enabledRentSystem()) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("MarketDisabled"));
            return;
        }
        if (plugin.getTransactionManager().isForSale(landName)) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("SellRentFail"));
            return;
        }
        final ClaimedResidence res = plugin.getResidenceManager().getByName(landName);
        if (res == null) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("InvalidResidence"));
            return;
        }
        if (!resadmin) {
            if (!res.getPermissions().hasResidencePermission(player, true)) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("NoPermission"));
                return;
            }
            final PermissionGroup group = plugin.getPermissionManager().getGroup(player);
            if (this.getRentableCount(player.getName()) >= group.getMaxRentables()) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceMaxRent"));
                return;
            }
        }
        if (!rentableLand.containsKey(landName)) {
            final ResidenceRentEvent revent = new ResidenceRentEvent(res, player, RentEventType.RENTABLE);
            pm.callEvent(revent);
            if (revent.isCancelled()) {
                return;
            }
            final RentableLand newrent = new RentableLand();
            newrent.days = days;
            newrent.cost = amount;
            newrent.repeatable = repeatable;
            rentableLand.put(landName, newrent);
            final String[] split = landName.split("\\.");
            if (split.length != 0) {
                player.sendMessage(ChatColor.GREEN + plugin.getLanguage().getPhrase("ResidenceForRentSuccess",
                        ChatColor.YELLOW + split[split.length - 1] + ChatColor.GREEN + "." + ChatColor.YELLOW + amount + ChatColor.GREEN + "." + ChatColor.YELLOW + days + ChatColor.GREEN));
            }
        } else {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceAlreadyRent"));
        }
    }

    public void setRentedRepeatable(final Player player, final String landName, final boolean value, final boolean resadmin) {
        final String[] split = landName.split("\\.");
        final RentedLand land = rentedLand.get(landName);
        if (land != null && (land.player.equals(player.getName()) || resadmin)) {
            land.autoRefresh = value;
            if (value && split.length != 0) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("RentEnableRenew", ChatColor.YELLOW + split[split.length - 1] + ChatColor.RED));
            } else if (split.length != 0) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("RentDisableRenew", ChatColor.YELLOW + split[split.length - 1] + ChatColor.RED));
            }
        }
    }

    public void setRentRepeatable(final Player player, final String landName, final boolean value, final boolean resadmin) {
        final String[] split = landName.split("\\.");
        final RentableLand land = rentableLand.get(landName);
        final ClaimedResidence res = plugin.getResidenceManager().getByName(landName);
        if (land != null && res != null && (res.getPermissions().getOwner().equalsIgnoreCase(player.getName()) || resadmin)) {
            land.repeatable = value;
            if (!value && this.isRented(landName)) {
                rentedLand.get(landName).autoRefresh = false;
            }
            if (value && split.length != 0) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("RentableEnableRenew", ChatColor.YELLOW + split[split.length - 1] + ChatColor.RED));
            } else if (split.length != 0) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("RentableDisableRenew", ChatColor.YELLOW + split[split.length - 1] + ChatColor.RED));
            }
        }
    }

    public void unrent(final Player player, final String landName, final boolean resadmin) {
        final String[] split = landName.split("\\.");
        final ClaimedResidence res = plugin.getResidenceManager().getByName(landName);
        if (res == null) {
            player.sendMessage(ChatColor.YELLOW + plugin.getLanguage().getPhrase("InvalidResidence"));
            return;
        }
        if (!res.getPermissions().hasResidencePermission(player, true) && !resadmin) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("NoPermission"));
            return;
        }
        if (rentedLand.containsKey(landName) && !resadmin) {
            if (split.length != 0) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceAlreadyRented",
                        ChatColor.YELLOW + split[split.length - 1] + ChatColor.RED + "." + ChatColor.YELLOW + rentedLand.get(landName).player) + ChatColor.YELLOW);
            }
            return;
        }
        if (rentableLand.containsKey(landName)) {
            final ResidenceRentEvent revent = new ResidenceRentEvent(res, player, RentEventType.UNRENT);
            pm.callEvent(revent);
            if (revent.isCancelled()) {
                return;
            }
            rentableLand.remove(landName);
            if (rentedLand.containsKey(landName)) {
                rentedLand.remove(landName);
                res.getPermissions().applyDefaultFlags();
            }
            if (split.length != 0) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceRemoveRentable", ChatColor.YELLOW + split[split.length - 1] + ChatColor.RED));
            }

        } else {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("ResidenceNotForRent"));
        }
    }

    public void updateRentableName(final String oldName, final String newName) {
        if (rentableLand.containsKey(oldName)) {
            rentableLand.put(newName, rentableLand.get(oldName));
            rentableLand.remove(oldName);
        }
        if (rentedLand.containsKey(oldName)) {
            rentedLand.put(newName, rentedLand.get(oldName));
            rentedLand.remove(oldName);
        }
    }

    private long daysToMs(final int days) {
        return ((days) * 24L * 60L * 60L * 1000L);
    }

    @SuppressWarnings("unused")
    private int msToDays(final long ms) {
        return (int) Math.ceil((((ms / 1000D) / 60D) / 60D) / 24D);
    }
}
