/*
 * Copyright 2015-present 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.routing.bgp;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;

import java.util.Collection;

/**
 * Class for handling the remote BGP Peer session.
 */
class TestBgpPeerChannelHandler extends SimpleChannelHandler {
    static final long PEER_AS = 65001;
    static final long PEER_AS4 = 0x12345678;
    static final int PEER_HOLDTIME = 120;       // 120 seconds

    final BgpSessionInfo localInfo = new BgpSessionInfo();
    ChannelHandlerContext savedCtx;

    /**
     * Constructor for given BGP ID.
     *
     * @param bgpId the BGP ID to use
     */
    TestBgpPeerChannelHandler(Ip4Address bgpId) {
        this.localInfo.setBgpVersion(BgpConstants.BGP_VERSION);
        this.localInfo.setBgpId(bgpId);
        this.localInfo.setAsNumber(PEER_AS);
        this.localInfo.setHoldtime(PEER_HOLDTIME);
    }

    /**
     * Closes the channel.
     */
    void closeChannel() {
        savedCtx.getChannel().close();
    }

    @Override
    public void channelConnected(ChannelHandlerContext ctx,
                                 ChannelStateEvent channelEvent) {
        this.savedCtx = ctx;
        // Prepare and transmit BGP OPEN message
        ChannelBuffer message = BgpOpen.prepareBgpOpen(localInfo);
        ctx.getChannel().write(message);

        // Prepare and transmit BGP KEEPALIVE message
        message = BgpKeepalive.prepareBgpKeepalive();
        ctx.getChannel().write(message);
    }

    @Override
    public void channelDisconnected(ChannelHandlerContext ctx,
                                    ChannelStateEvent channelEvent) {
        // Nothing to do
    }

    /**
     * Prepares BGP UPDATE message.
     *
     * @param nextHopRouter the next-hop router address for the routes to add
     * @param localPref the local preference for the routes to use
     * @param multiExitDisc the MED value
     * @param asPath the AS path for the routes to add
     * @param addedRoutes the routes to add
     * @param withdrawnRoutes the routes to withdraw
     * @return the message to transmit (BGP header included)
     */
    ChannelBuffer prepareBgpUpdate(Ip4Address nextHopRouter,
                                   long localPref,
                                   long multiExitDisc,
                                   BgpRouteEntry.AsPath asPath,
                                   Collection<Ip4Prefix> addedRoutes,
                                   Collection<Ip4Prefix> withdrawnRoutes) {
        int attrFlags;
        ChannelBuffer message =
            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
        ChannelBuffer pathAttributes =
            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);

        // Encode the Withdrawn Routes
        ChannelBuffer encodedPrefixes = encodePackedPrefixes(withdrawnRoutes);
        message.writeShort(encodedPrefixes.readableBytes());
        message.writeBytes(encodedPrefixes);

        // Encode the Path Attributes
        // ORIGIN: IGP
        attrFlags = 0x40;                               // Transitive flag
        pathAttributes.writeByte(attrFlags);
        pathAttributes.writeByte(BgpConstants.Update.Origin.TYPE);
        pathAttributes.writeByte(1);                    // Data length
        pathAttributes.writeByte(BgpConstants.Update.Origin.IGP);

        // AS_PATH: asPath
        attrFlags = 0x40;                               // Transitive flag
        pathAttributes.writeByte(attrFlags);
        pathAttributes.writeByte(BgpConstants.Update.AsPath.TYPE);
        ChannelBuffer encodedAsPath = encodeAsPath(asPath);
        pathAttributes.writeByte(encodedAsPath.readableBytes()); // Data length
        pathAttributes.writeBytes(encodedAsPath);
        // NEXT_HOP: nextHopRouter
        attrFlags = 0x40;                               // Transitive flag
        pathAttributes.writeByte(attrFlags);
        pathAttributes.writeByte(BgpConstants.Update.NextHop.TYPE);
        pathAttributes.writeByte(4);                    // Data length
        pathAttributes.writeInt(nextHopRouter.toInt()); // Next-hop router
        // LOCAL_PREF: localPref
        attrFlags = 0x40;                               // Transitive flag
        pathAttributes.writeByte(attrFlags);
        pathAttributes.writeByte(BgpConstants.Update.LocalPref.TYPE);
        pathAttributes.writeByte(4);                    // Data length
        pathAttributes.writeInt((int) localPref);       // Preference value
        // MULTI_EXIT_DISC: multiExitDisc
        attrFlags = 0x80;                               // Optional
                                                        // Non-Transitive flag
        pathAttributes.writeByte(attrFlags);
        pathAttributes.writeByte(BgpConstants.Update.MultiExitDisc.TYPE);
        pathAttributes.writeByte(4);                    // Data length
        pathAttributes.writeInt((int) multiExitDisc);   // Preference value
        // The NLRI prefixes
        encodedPrefixes = encodePackedPrefixes(addedRoutes);

        // Write the Path Attributes, beginning with its length
        message.writeShort(pathAttributes.readableBytes());
        message.writeBytes(pathAttributes);
        message.writeBytes(encodedPrefixes);

        return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_UPDATE,
                                            message);
    }

    /**
     * Encodes a collection of IPv4 network prefixes in a packed format.
     * <p>
     * The IPv4 prefixes are encoded in the form:
     * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
     * and Prefix is the IPv4 prefix (padded with trailing bits to the end
     * of an octet).
     *
     * @param prefixes the prefixes to encode
     * @return the buffer with the encoded prefixes
     */
    private ChannelBuffer encodePackedPrefixes(Collection<Ip4Prefix> prefixes) {
        ChannelBuffer message =
            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);

        // Write each of the prefixes
        for (Ip4Prefix prefix : prefixes) {
            int prefixBitlen = prefix.prefixLength();
            int prefixBytelen = (prefixBitlen + 7) / 8;         // Round-up
            message.writeByte(prefixBitlen);

            Ip4Address address = prefix.address();
            long value = address.toInt() & 0xffffffffL;
            for (int i = 0; i < Ip4Address.BYTE_LENGTH; i++) {
                if (prefixBytelen-- == 0) {
                    break;
                }
                long nextByte =
                    (value >> ((Ip4Address.BYTE_LENGTH - i - 1) * 8)) & 0xff;
                message.writeByte((int) nextByte);
            }
        }

        return message;
    }

    /**
     * Encodes an AS path.
     *
     * @param asPath the AS path to encode
     * @return the buffer with the encoded AS path
     */
    private ChannelBuffer encodeAsPath(BgpRouteEntry.AsPath asPath) {
        ChannelBuffer message =
            ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);

        for (BgpRouteEntry.PathSegment pathSegment : asPath.getPathSegments()) {
            message.writeByte(pathSegment.getType());
            message.writeByte(pathSegment.getSegmentAsNumbers().size());
            for (Long asNumber : pathSegment.getSegmentAsNumbers()) {
                message.writeShort(asNumber.intValue());
            }
        }

        return message;
    }
}
