package org.jivesoftware.openfire.plugin;

import org.jivesoftware.openfire.group.Group;
import org.jivesoftware.openfire.group.GroupManager;
import org.jivesoftware.openfire.group.GroupNotFoundException;
import org.jivesoftware.openfire.plugin.rules.Rule;
import org.jivesoftware.openfire.plugin.rules.RuleManager;
import org.jivesoftware.util.Log;
import org.xmpp.packet.*;

public class PacketFilter {

    private static PacketFilter packetFilter = new PacketFilter();
    RuleManager ruleManager;

    private PacketFilter() {

    }

    public static PacketFilter getInstance() {
        return packetFilter;
    }

    public void setRuleManager(RuleManager ruleManager) {
        this.ruleManager = ruleManager;
    }

    public Rule findMatch(Packet packet) {
        if (packet.getTo() == null || packet.getFrom() == null) return null;
        //TODO Would it be better to keep a local copy of the rules?
        for (Rule rule : ruleManager.getRules()) {
            if (!rule.isDisabled() &&
                    typeMatch(rule.getPackeType(), packet) &&
                    sourceDestMatch(rule.getDestType(), rule.getDestination(), packet.getTo()) &&
                    sourceDestMatch(rule.getSourceType(), rule.getSource(), packet.getFrom())) {

                return rule;
            }
        }
        return null;
    }

    private boolean typeMatch(Rule.PacketType rulePacketType, Packet packet) {
        //Simple case. Any.
        if (rulePacketType == Rule.PacketType.Any) return true;

        else if (packet instanceof Message) {
            Message message = (Message) packet;
            if (rulePacketType == Rule.PacketType.Message) {
                return true;
            }
            //Try some types.
            else if (rulePacketType == Rule.PacketType.MessageChat
                    && message.getType() == Message.Type.chat) {
                return true;
            } else if (rulePacketType == Rule.PacketType.MessageGroupChat
                    && message.getType() ==  Message.Type.groupchat) {
                return true;
            }
            return false;
        } else if (packet instanceof Presence) {
            if (rulePacketType == Rule.PacketType.Presence) {
                return true;
            } else return false;
        } else if (packet instanceof IQ) {
            if (rulePacketType == Rule.PacketType.Iq) {
                return true;
            } else return false;
        }

        return false;
    }


    private boolean sourceDestMatch(Rule.SourceDestType type, String ruleToFrom, JID packetToFrom) {
        if (type == Rule.SourceDestType.Any) return true;
        if (type == Rule.SourceDestType.User) {
            if (ruleToFrom.equals(packetToFrom.toBareJID())) {
                return true;
            }
        } else if (type == Rule.SourceDestType.Group) {
            return packetToFromGroup(ruleToFrom, packetToFrom);
        } else if (type == Rule.SourceDestType.Component) {
            if (ruleToFrom.toLowerCase().equals(packetToFrom.getDomain().toLowerCase())) {
                return true;
            }
        } else if (type == Rule.SourceDestType.Other) {
            if (matchUser(ruleToFrom, packetToFrom)) {
                return true;
            }
        }
        return false;
    }

    private boolean matchUser(String ruleToFrom, JID packetToFrom) {
        boolean match = false;
        //Escape the text so I get a rule to packet match. 
       // String escapedPacketToFrom = JID.unescapeNode(packetToFrom.toBareJID().toString());
        if (ruleToFrom.indexOf("*") == 0 && ruleToFrom.indexOf("@") == 1) {
            if (PacketFilterUtil.getDomain(ruleToFrom).equals(packetToFrom.getDomain().toString())) {
                match = true;
            }
        } else {     
            if (ruleToFrom.equals(packetToFrom.toBareJID())) {
                match = true;
            }
        }
        return match;
    }


    private boolean packetToFromGroup(String rulegroup, JID packetToFrom) {
        Group group = null;
        try {
            group = GroupManager.getInstance().getProvider().getGroup(rulegroup);
        } catch (GroupNotFoundException e) {
            e.printStackTrace();
        }
        if (group == null) {
            return false;
        } else {
            if (group.isUser(packetToFrom)) {
                return true;
            }
        }
        return false;
    }
}
