/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onosproject.net.group;

import static com.google.common.base.MoreObjects.toStringHelper;

import java.util.Objects;

import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;

/**
 * ONOS implementation of default group that is stored in the system.
 */
public class DefaultGroup extends DefaultGroupDescription
    implements Group, StoredGroupEntry {

    private GroupState state;
    private boolean isGroupStateAddedFirstTime;
    private long life;
    private long packets;
    private long bytes;
    private long referenceCount;
    private GroupId id;

    /**
     * Default group object constructor with the parameters.
     *
     * @param id group identifier
     * @param groupDesc group description parameters
     */
    public DefaultGroup(GroupId id, GroupDescription groupDesc) {
        super(groupDesc);
        this.id = id;
        this.state = GroupState.PENDING_ADD;
        this.life = 0;
        this.packets = 0;
        this.bytes = 0;
        this.referenceCount = 0;
    }

    /**
     * Default group object constructor with the available information
     * from data plane.
     *
     * @param id group identifier
     * @param deviceId device identifier
     * @param type type of the group
     * @param buckets immutable list of group bucket
     */
    public DefaultGroup(GroupId id,
                        DeviceId deviceId,
                        GroupDescription.Type type,
                        GroupBuckets buckets) {
        super(deviceId, type, buckets);
        this.id = id;
        this.state = GroupState.PENDING_ADD;
        this.life = 0;
        this.packets = 0;
        this.bytes = 0;
        this.referenceCount = 0;
    }

    /**
     * Returns group identifier associated with a group object.
     *
     * @return GroupId Group Identifier
     */
    @Override
    public GroupId id() {
        return this.id;
    }

    /**
     * Returns current state of a group object.
     *
     * @return GroupState Group State
     */
    @Override
    public GroupState state() {
        return this.state;
    }

    /**
     * Returns the number of milliseconds this group has been alive.
     *
     * @return number of millis
     */
    @Override
    public long life() {
        return this.life;
    }

    /**
     * Returns the number of packets processed by this group.
     *
     * @return number of packets
     */
    @Override
    public long packets() {
        return this.packets;
    }

    /**
     * Returns the number of bytes processed by this group.
     *
     * @return number of bytes
     */
    @Override
    public long bytes() {
        return this.bytes;
    }

    /**
     * Sets the new state for this entry.
     *
     * @param newState new group entry state.
     */
    @Override
    public void setState(Group.GroupState newState) {
        this.state = newState;
    }

    /**
     * Sets how long this entry has been entered in the system.
     *
     * @param life epoch time
     */
    @Override
    public void setLife(long life) {
        this.life = life;
    }

    /**
     * Sets number of packets processed by this group entry.
     *
     * @param packets a long value
     */
    @Override
    public void setPackets(long packets) {
        this.packets = packets;
    }

    /**
     * Sets number of bytes processed by this group entry.
     *
     * @param bytes a long value
     */
    @Override
    public void setBytes(long bytes) {
        this.bytes = bytes;
    }

    @Override
    public void setReferenceCount(long referenceCount) {
        this.referenceCount = referenceCount;
    }

    @Override
    public long referenceCount() {
        return referenceCount;
    }

    /*
     * The deviceId, type and buckets are used for hash.
     *
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public int hashCode() {
        return super.hashCode() + Objects.hash(id);
    }

    /*
     * The deviceId, groupId, type and buckets should be same.
     *
     * (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
       if (obj instanceof DefaultGroup) {
            DefaultGroup that = (DefaultGroup) obj;
            return super.equals(obj) &&
                    Objects.equals(id, that.id);
        }
        return false;
    }

    @Override
    public String toString() {
        return toStringHelper(this)
                .add("description", super.toString())
                .add("groupid", id)
                .add("state", state)
                .toString();
    }

    @Override
    public void setIsGroupStateAddedFirstTime(boolean isGroupStateAddedFirstTime) {
        this.isGroupStateAddedFirstTime = isGroupStateAddedFirstTime;
    }

    @Override
    public boolean isGroupStateAddedFirstTime() {
        return isGroupStateAddedFirstTime;
    }
}

@@ -1194,16 +1194,315 @@
 Id id;%0A%0A
+    /**%0A     * Initializes default values.%0A     *%0A     * @param newId group id for new group%0A     */%0A    private void initialize(GroupId newId) %7B%0A        id = newId;%0A        state = GroupState.PENDING_ADD;%0A        life = 0;%0A        packets = 0;%0A        bytes = 0;%0A        referenceCount = 0;%0A    %7D%0A%0A
     /**%0A
@@ -1562,16 +1562,16 @@
 meters.%0A
-
      *%0A 
@@ -1768,171 +1768,22 @@
     
-this.id = id;%0A        this.state = GroupState.PENDING_ADD;%0A        this.life = 0;%0A        this.packets = 0;%0A        this.bytes = 0;%0A        this.referenceCount = 0
+initialize(id)
 ;%0A  
@@ -2301,171 +2301,22 @@
     
-this.id = id;%0A        this.state = GroupState.PENDING_ADD;%0A        this.life = 0;%0A        this.packets = 0;%0A        this.bytes = 0;%0A        this.referenceCount = 0
+initialize(id)
 ;%0A  

Eliminate code duplication in initialization