/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

#include <axis2_flow.h>

struct axis2_flow
{
    axutil_array_list_t *list;
};

AXIS2_EXTERN axis2_flow_t *AXIS2_CALL
axis2_flow_create(
    const axutil_env_t * env)
{
    axis2_flow_t *flow = NULL;

    flow = (axis2_flow_t *)AXIS2_MALLOC(env->allocator, sizeof(axis2_flow_t));

    if(!flow)
    {
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        return NULL;
    }

    flow->list = NULL;

    flow->list = axutil_array_list_create(env, 20);
    if(!(flow->list))
    {
        axis2_flow_free(flow, env);
        AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
        return NULL;
    }

    return flow;
}

AXIS2_EXTERN void AXIS2_CALL
axis2_flow_free(
    axis2_flow_t * flow,
    const axutil_env_t * env)
{
    if(flow->list)
    {
        int i = 0;
        int size = 0;

        size = axutil_array_list_size(flow->list, env);
        for(i = 0; i < size; i++)
        {
            axis2_handler_desc_t *handler_desc = NULL;

            handler_desc = (axis2_handler_desc_t *)axutil_array_list_get(flow->list, env, i);
            axis2_handler_desc_free(handler_desc, env);
        }
        axutil_array_list_free(flow->list, env);
    }

    if(flow)
    {
        AXIS2_FREE(env->allocator, flow);
    }

    return;
}

AXIS2_EXTERN void AXIS2_CALL
axis2_flow_free_void_arg(
    void *flow,
    const axutil_env_t * env)
{
    axis2_flow_t *flow_l = NULL;

    flow_l = (axis2_flow_t *)flow;
    axis2_flow_free(flow_l, env);
    return;
}

AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_flow_add_handler(
    axis2_flow_t * flow,
    const axutil_env_t * env,
    axis2_handler_desc_t * handler)
{
    AXIS2_PARAM_CHECK(env->error, handler, AXIS2_FAILURE);

    if(!flow->list)
    {
        flow->list = axutil_array_list_create(env, 0);
        if(!flow->list)
        {
            axis2_flow_free(flow, env);
            AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
            return AXIS2_FAILURE;
        }
    }
    return axutil_array_list_add(flow->list, env, handler);
}

AXIS2_EXTERN axis2_handler_desc_t *AXIS2_CALL
axis2_flow_get_handler(
    const axis2_flow_t * flow,
    const axutil_env_t * env,
    const int index)
{
    return axutil_array_list_get(flow->list, env, index);
}

AXIS2_EXTERN int AXIS2_CALL
axis2_flow_get_handler_count(
    const axis2_flow_t * flow,
    const axutil_env_t * env)
{
    return axutil_array_list_size(flow->list, env);
}

