/****************************************************************************/
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
// Copyright (C) 2017-2019 German Aerospace Center (DLR) and others.
// TraCI4J module
// Copyright (C) 2011 ApPeAL Group, Politecnico di Torino
// This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v2.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v20.html
// SPDX-License-Identifier: EPL-2.0
/****************************************************************************/
/// @file    ResponseMessage.java
/// @author  Enrico Gueli
/// @author  Mario Krumnow
/// @date    2011
///
//
/****************************************************************************/
package it.polito.appeal.traci.protocol;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import de.tudresden.sumo.config.Constants;
import de.uniluebeck.itm.tcpip.Storage;

/**
 * Represents a message sent from the server. A response message is made of an
 * ordered collection of status responses, response commands and/or sub-responses.
 * @author Enrico Gueli &lt;enrico.gueli@polito.it&gt;
 *
 */
public class ResponseMessage {

    /**
     * The list of IDs of responses that have no response commands.
     */
    public static final int[] STATUS_ONLY_RESPONSES = new int[] {
        Constants.CMD_CLOSE,
        Constants.CMD_SETORDER,
        Constants.CMD_SET_EDGE_VARIABLE,
        Constants.CMD_SET_GUI_VARIABLE,
        Constants.CMD_SET_LANE_VARIABLE,
        Constants.CMD_SET_PERSON_VARIABLE,
        Constants.CMD_SET_POI_VARIABLE,
        Constants.CMD_SET_POLYGON_VARIABLE,
        Constants.CMD_SET_ROUTE_VARIABLE,
        Constants.CMD_SET_SIM_VARIABLE,
        Constants.CMD_SET_TL_VARIABLE,
        Constants.CMD_SET_VEHICLE_VARIABLE,
        Constants.CMD_SET_VEHICLETYPE_VARIABLE
    };

    private List<ResponseContainer> pairs = new ArrayList<ResponseContainer>();

    /**
     * Constructor that unpacks all the data from a {@link DataInputStream},
     * populating the list of {@link ResponseContainer}s.
     * <p>
     * A response message is made of individual packets. It is assumed that the
     * first packet is always a status response. According to the status
     * response, different data are expected next:
     * <ul>
     * <li>if the status response is not {@link Constants#RTYPE_OK}, another
     * status response or the end of the stream are expected.</li>
     * <li>if the status ID is equal to {@link Constants#CMD_SIMSTEP}, it is
     * expected an integer representing N and N following sub-responses;</li>
     * <li>if the status ID matches one of the commands in
     * {@link #STATUS_ONLY_RESPONSES} , it is expected another status response;
     * <li>if the status ID doesn't match any of the above, it is expected a
     * response command.
     * </ul>
     * A new {@link ResponseMessage}, collecting all the data that belong to the
     * same request, is built and appended to an internal list.
     *
     * @param dis dis
     * @throws IOException Exception
     */
    public ResponseMessage(DataInputStream dis) throws IOException {
        int totalLen = dis.readInt() - Integer.SIZE / 8;

        byte[] buffer = new byte[totalLen];
        dis.readFully(buffer);
        //StringBuilder sb = new StringBuilder();
        //for (byte b : buffer) {
        //    sb.append(String.format("%X ", b));
        //}
        //System.out.println("ResponseMessage::init buffer=" + sb);

        Storage s = new Storage(buffer);

        while (s.validPos()) {
            StatusResponse sr = new StatusResponse(s);
            ResponseContainer responseContainer;

            if (sr.result() != Constants.RTYPE_OK) {
                responseContainer = new ResponseContainer(sr, null);
            } else if (sr.id() == Constants.CMD_SIMSTEP) {
                int nSubResponses = s.readInt();
                List<Command> subResponses = new ArrayList<Command>(
                    nSubResponses);
                for (int i = 0; i < nSubResponses; i++) {
                    subResponses.add(new Command(s));
                }

                responseContainer = new ResponseContainer(sr, null, subResponses);

            } else if (isStatusOnlyResponse(sr.id())) {
                responseContainer = new ResponseContainer(sr, null);
            } else {
                responseContainer = new ResponseContainer(sr, new Command(s));
            }

            pairs.add(responseContainer);
        }
    }

    private boolean isStatusOnlyResponse(int statusResponseID) {
        for (int id : STATUS_ONLY_RESPONSES)
            if (id == statusResponseID) {
                return true;
            }
        return false;
    }

    public List<ResponseContainer> responses() {
        return Collections.unmodifiableList(pairs);
    }


}
