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

package com.bekvon.bukkit.residence.protection;

import java.util.Collections;
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 com.bekvon.bukkit.residence.event.ResidenceDeleteEvent;
import com.bekvon.bukkit.residence.event.ResidenceDeleteEvent.DeleteCause;
import com.bekvon.bukkit.residence.permissions.PermissionGroup;

import pw.yumc.Residence.ResidenceMain;
import pw.yumc.Residence.economy.EconomyInterface;

/**
 *
 * @author Administrator
 */
public class LeaseManager {

    private Map<String, Long> leaseExpireTime;

    ResidenceManager manager;
    ResidenceMain plugin;

    public LeaseManager(final ResidenceMain plugin, final ResidenceManager m) {
        this.plugin = plugin;
        manager = m;
        leaseExpireTime = Collections.synchronizedMap(new HashMap<String, Long>());
    }

    public static LeaseManager load(final ResidenceMain plugin, final Map<String, Long> root, final ResidenceManager m) {
        final LeaseManager l = new LeaseManager(plugin, m);
        if (root != null) {
            for (final Object val : root.values()) {
                if (!(val instanceof Long)) {
                    root.remove(val);
                }
            }
            l.leaseExpireTime = Collections.synchronizedMap(root);
        }
        return l;
    }

    public void doExpirations() {
        final Set<Entry<String, Long>> set = leaseExpireTime.entrySet();
        final Iterator<Entry<String, Long>> it = set.iterator();
        while (it.hasNext()) {
            final Entry<String, Long> next = it.next();
            if (next.getValue() <= System.currentTimeMillis()) {
                final String resname = next.getKey();
                final ClaimedResidence res = plugin.getResidenceManager().getByName(resname);
                if (res == null) {
                    it.remove();
                } else {
                    boolean renewed = false;
                    final String owner = res.getPermissions().getOwner();
                    final PermissionGroup limits = plugin.getPermissionManager().getGroup(owner, res.getPermissions().getWorld());
                    final int cost = this.getRenewCost(res);
                    if (plugin.getConfigManager().enableEconomy() && plugin.getConfigManager().autoRenewLeases()) {
                        if (cost == 0) {
                            renewed = true;
                        } else if (res.getBank().hasEnough(cost)) {
                            res.getBank().subtract(cost);
                            renewed = true;
                            if (plugin.getConfigManager().debugEnabled()) {
                                plugin.getLogger().info("Lease Renewed From Residence Bank: " + resname);
                            }
                        } else if (plugin.getEconomyManager().canAfford(owner, cost)) {
                            if (plugin.getEconomyManager().subtract(owner, cost)) {
                                renewed = true;
                                if (plugin.getConfigManager().debugEnabled()) {
                                    plugin.getLogger().info("Lease Renewed From Economy: " + resname);
                                }
                            }
                        }
                    }
                    if (!renewed) {
                        if (!plugin.getConfigManager().enabledRentSystem() || !plugin.getRentManager().isRented(resname)) {
                            final ResidenceDeleteEvent resevent = new ResidenceDeleteEvent(null, res, DeleteCause.LEASE_EXPIRE);
                            plugin.getServer().getPluginManager().callEvent(resevent);
                            if (!resevent.isCancelled()) {
                                manager.removeResidence(next.getKey());
                                it.remove();
                                if (plugin.getConfigManager().debugEnabled()) {
                                    plugin.getLogger().info("Lease NOT removed, Removing: " + resname);
                                }
                            }
                        }
                    } else {
                        if (plugin.getConfigManager().enableEconomy() && plugin.getConfigManager().enableLeaseMoneyAccount()) {
                            plugin.getEconomyManager().add("Lease Money", cost);
                        }
                        if (plugin.getConfigManager().debugEnabled()) {
                            plugin.getLogger().info("Lease Renew Old: " + next.getValue());
                        }
                        next.setValue(System.currentTimeMillis() + daysToMs(limits.getLeaseGiveTime()));
                        if (plugin.getConfigManager().debugEnabled()) {
                            plugin.getLogger().info("Lease Renew New: " + next.getValue());
                        }
                    }
                }
            }
        }
    }

    public Date getExpireTime(final String area) {
        if (leaseExpireTime.containsKey(area)) {
            return new Date(leaseExpireTime.get(area));
        }
        return null;
    }

    public int getRenewCost(final ClaimedResidence res) {
        final PermissionGroup limits = plugin.getPermissionManager().getGroup(res.getPermissions().getOwner(), res.getPermissions().getWorld());
        final double cost = limits.getLeaseRenewCost();
        final int amount = (int) Math.ceil(res.getTotalSize() * cost);
        return amount;
    }

    public boolean leaseExpires(final String area) {
        return leaseExpireTime.containsKey(area);
    }

    public void removeExpireTime(final String area) {
        leaseExpireTime.remove(area);
    }

    public void renewArea(final String area, final Player player) {
        if (!leaseExpires(area)) {
            player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("LeaseNotExpire"));
            return;
        }
        final PermissionGroup limits = plugin.getPermissionManager().getGroup(player);
        final int max = limits.getMaxLeaseTime();
        final int add = limits.getLeaseGiveTime();
        final int rem = daysRemaining(area);
        final EconomyInterface econ = plugin.getEconomyManager();
        if (econ != null) {
            final double cost = limits.getLeaseRenewCost();
            final ClaimedResidence res = manager.getByName(area);
            final int amount = (int) Math.ceil(res.getTotalSize() * cost);
            if (cost != 0D) {
                if (econ.canAfford(player.getName(), amount)) {
                    econ.subtract(player.getName(), amount);
                    econ.add("Lease Money", amount);
                    player.sendMessage(ChatColor.GREEN + plugin.getLanguage().getPhrase("MoneyCharged",
                            ChatColor.YELLOW + String.format("%d", amount) + ChatColor.GREEN + "." + ChatColor.YELLOW + econ.getName() + ChatColor.GREEN));
                } else {
                    player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("NotEnoughMoney"));
                    return;
                }
            }
        }
        if (rem + add > max) {
            setExpireTime(player, area, max);
            player.sendMessage(ChatColor.GOLD + plugin.getLanguage().getPhrase("LeaseRenewMax"));
            player.sendMessage(ChatColor.YELLOW + plugin.getLanguage().getPhrase("LeaseRenew", ChatColor.GREEN + "" + getExpireTime(area)) + ChatColor.YELLOW);
            return;
        }
        Long get = leaseExpireTime.get(area);
        if (get != null) {
            get = get + daysToMs(add);
            leaseExpireTime.put(area, get);
        } else {
            leaseExpireTime.put(area, daysToMs(add));
        }
        player.sendMessage(ChatColor.YELLOW + plugin.getLanguage().getPhrase("LeaseRenew", ChatColor.GREEN + "" + getExpireTime(area)));
    }

    public void resetLeases() {
        leaseExpireTime.clear();
        final String[] list = manager.getResidenceList();
        for (final String element : list) {
            if (element != null) {
                final ClaimedResidence res = plugin.getResidenceManager().getByName(element);
                final PermissionGroup group = plugin.getPermissionManager().getGroup(res.getPermissions().getOwner(), res.getPermissions().getWorld());
                this.setExpireTime(null, element, group.getLeaseGiveTime());
            }
        }
        plugin.getLogger().info(" - Set default leases.");
    }

    public Map<String, Long> save() {
        return leaseExpireTime;
    }

    public void setExpireTime(final Player player, String area, final int days) {
        area = area.replace(".", "_");
        if (manager.getByName(area) != null) {
            leaseExpireTime.put(area, daysToMs(days) + System.currentTimeMillis());
            if (player != null) {
                player.sendMessage(ChatColor.GREEN + plugin.getLanguage().getPhrase("LeaseRenew", getExpireTime(area).toString()));
            }
        } else {
            if (player != null) {
                player.sendMessage(ChatColor.RED + plugin.getLanguage().getPhrase("InvalidArea"));
            }
        }
    }

    public void setExpireTime(final String area, final int days) {
        this.setExpireTime(null, area, days);
    }

    public void updateLeaseName(final String oldName, final String newName) {
        if (leaseExpireTime.containsKey(oldName)) {
            leaseExpireTime.put(newName, leaseExpireTime.get(oldName));
            leaseExpireTime.remove(oldName);
        }
    }

    private int daysRemaining(final String area) {
        final Long get = leaseExpireTime.get(area);
        if (get <= System.currentTimeMillis()) {
            return 0;
        }
        return msToDays((int) (get - System.currentTimeMillis()));
    }

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

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