/*
 * Copyright (c) 2015, Mazen Kotb <email@mazenmc.io>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
package io.minecloud.models.network;

import com.mongodb.BasicDBObject;
import com.mongodb.DBRef;
import io.minecloud.MineCloud;
import io.minecloud.db.mongo.model.MongoEntity;
import io.minecloud.models.bungee.Bungee;
import io.minecloud.models.bungee.type.BungeeType;
import io.minecloud.models.bungee.type.BungeeTypeRepository;
import io.minecloud.models.network.server.ServerMetadata;
import io.minecloud.models.nodes.Node;
import io.minecloud.models.server.Server;
import io.minecloud.models.server.type.ServerType;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.annotations.Id;
import org.mongodb.morphia.annotations.Reference;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Entity(value = "networks", noClassnameStored = true)
@EqualsAndHashCode(callSuper = true)
public class Network extends MongoEntity {
    @Setter
    private List<ServerMetadata> serverMetadata;
    @Setter
    private Map<String, Integer> bungees;
    @Setter
    @Reference
    private List<Node> nodes;

    public String name() {
        return entityId();
    }

    public List<ServerMetadata> serverMetadata() {
        return serverMetadata;
    }

    public Map<BungeeType, Integer> bungeeMetadata() {
        Map<BungeeType, Integer> metadata = new HashMap<>();

        if (bungees == null) {
            return metadata;
        }

        for (Map.Entry<String, Integer> entry : bungees.entrySet()) {
            BungeeTypeRepository repository = MineCloud.instance().mongo().repositoryBy(BungeeType.class);

            metadata.put(repository.findFirst(entry.getKey()), entry.getValue());
        }

        return metadata;
    }

    public int serversOnline() {
        return (int) MineCloud.instance().mongo().repositoryBy(Server.class)
                .count("network", this);
    }

    public int serversOnline(ServerType type) {
        return (int) MineCloud.instance().mongo().repositoryBy(Server.class).collection()
                .count(new BasicDBObject("network", new DBRef("networks", entityId()))
                        .append("type", new DBRef("type", type.entityId())));
    }

    public int bungeesOnline() {
        return (int) MineCloud.instance().mongo().repositoryBy(Bungee.class)
                .count("network", this);
    }

    public int bungeesOnline(BungeeType type) {
        return (int) MineCloud.instance().mongo().repositoryBy(Bungee.class).collection()
                .count(new BasicDBObject("network", new DBRef("networks", entityId()))
                        .append("type", new DBRef("type", type.entityId())));
    }

    public List<Node> nodes() {
        return nodes;
    }

    public void setName(String name) {
        setId(name);
    }

    public void setBungees(Map<BungeeType, Integer> map) {
        bungees = new HashMap<>();

        for (Map.Entry<BungeeType, Integer> entry : map.entrySet()) {
            bungees.put(entry.getKey().name(), entry.getValue());
        }
    }
}

@@ -1004,16 +1004,68 @@
 Bungee;%0A
+import io.minecloud.models.bungee.BungeeRepository;%0A
 import i
@@ -1303,24 +1303,76 @@
 ver.Server;%0A
+import io.minecloud.models.server.ServerRepository;%0A
 import io.mi
@@ -1604,16 +1604,108 @@
 ference;
+%0Aimport org.mongodb.morphia.query.FieldCriteria;%0Aimport org.mongodb.morphia.query.QueryImpl;
 %0A%0Aimport
@@ -2928,36 +2928,53 @@
 ) %7B%0A        
-return (int)
+ServerRepository repository =
  MineCloud.i
@@ -3021,107 +3021,118 @@
 ass)
-.collection()%0A                .count(new BasicDBObject(%22network%22, new DBRef(%22networks%22, entityId())
+;%0A%0A        return (int) repository.count(repository.createQuery()%0A                .field(%22network%22).equal(this
 )%0A  
@@ -3149,66 +3149,33 @@
     
- 
-       .append(%22type%22, new DBRef(%22type%22, type.entityId())
+.field(%22type%22).equal(type
 ));%0A
@@ -3391,36 +3391,53 @@
 ) %7B%0A        
-return (int)
+BungeeRepository repository =
  MineCloud.i
@@ -3484,183 +3484,161 @@
 ass)
-.collection()%0A                .count(new BasicDBObject(%22network%22, new DBRef(%22networks%22, entityId()))%0A                        .append(%22type%22, new DBRef(%22type%22, type.entityId())
+;%0A%0A        return (int) repository.count(repository.createQuery()%0A                .field(%22network%22).equal(this)%0A                .field(%22type%22).equal(type
 ));%0A

Fix another bug