/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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.
 */
#include <stdlib.h>
#include <algorithm>
#include "Log.h"
#include "StringUtil.h"
#include "task/TaskSequential.h"
#include "task/TaskCase.h"
#include "task/TaskAsync.h"

TaskSequential::TaskSequential()
    : TaskGeneric(TaskGeneric::ETaskSequential),
      mRepeatCount(1),
      mRepeatIndex(-1)
{

}

TaskSequential::~TaskSequential()
{

}


TaskGeneric::ExecutionResult TaskSequential::run()
{
    mRepeatIndex = -1;
    bool storeIndex = (mIndexName.length() == 0 ? false: true);
    if (storeIndex && !getTestCase()->registerIndex(mIndexName, mRepeatIndex)) {
        if (!getTestCase()->updateIndex(mIndexName, mRepeatIndex)) {
            LOGE("register/update of index %s failed", mIndexName.string());
            return TaskGeneric::EResultError;
        }
    }

    TaskGeneric::ExecutionResult firstError(TaskGeneric::EResultOK);

    for (mRepeatIndex = 0; mRepeatIndex < mRepeatCount; mRepeatIndex++) {
        LOGI("  TaskSequential index %s loop %d-th", mIndexName.string(), mRepeatIndex);
        if (storeIndex && !getTestCase()->updateIndex(mIndexName, mRepeatIndex)) {
            return TaskGeneric::EResultError;
        }
        std::list<TaskGeneric*>::iterator i = getChildren().begin();
        std::list<TaskGeneric*>::iterator end = getChildren().end();
        for (; i != end; i++) {
            TaskGeneric* child = *i;
            TaskGeneric::ExecutionResult result = child->run();
            if ((result != TaskGeneric::EResultOK) && (firstError == TaskGeneric::EResultOK)) {
                firstError = result;
                break;
            }
        }
        TaskGeneric::ExecutionResult result = runAsyncTasksQueued();
        if ((result != TaskGeneric::EResultOK) && (firstError == TaskGeneric::EResultOK)) {
                    firstError = result;
        }
        switch (firstError) {
        case TaskGeneric::EResultOK:
        case TaskGeneric::EResultContinue:
            // continue at the last index should be treated as OK
            firstError = TaskGeneric::EResultOK;
            break; // continue for loop
        case TaskGeneric:: EResultBreakOneLoop:
            return TaskGeneric::EResultOK;
        case TaskGeneric::EResultError:
        case TaskGeneric::EResultFail:
        case TaskGeneric::EResultPass:
            mRepeatIndex = mRepeatCount; //exit for loop
            break;
        }
    }
    // update to the loop exit value
    if (storeIndex && !getTestCase()->updateIndex(mIndexName, mRepeatIndex)) {
        return TaskGeneric::EResultError;
    }
    return firstError;
}

bool TaskSequential::queueAsyncTask(TaskAsync* task)
{
    std::list<TaskAsync*>::iterator it;
    it = std::find(mAsyncTasks.begin(), mAsyncTasks.end(), task);
    if (it != mAsyncTasks.end()) { // already queued
        return true;
    }
    mAsyncTasks.push_back(task);
    return true;
}

TaskGeneric::ExecutionResult TaskSequential::runAsyncTasksQueued()
{
    std::list<TaskAsync*>::iterator i = mAsyncTasks.begin();
    std::list<TaskAsync*>::iterator end = mAsyncTasks.end();
    TaskGeneric::ExecutionResult firstError(TaskGeneric::EResultOK);

    for (; i != end; i++) {
        TaskAsync* child = *i;
        TaskGeneric::ExecutionResult result = child->complete();
        if ((result != TaskGeneric::EResultOK) && (firstError == TaskGeneric::EResultOK)) {
            firstError = result;
        }
    }
    mAsyncTasks.clear();
    return firstError;
}


bool TaskSequential::parseAttribute(const android::String8& name, const android::String8& value)
{
    if (StringUtil::compare(name, "repeat") == 0) {
        mRepeatCount = atoi(value.string());
        if (mRepeatCount <= 0) {
            LOGE("TaskSequential::parseAttribute invalid value %s for key %s",
                    value.string(), name.string());
            return false;
        }
        return true;
    } else if (StringUtil::compare(name, "index") == 0) {
        mIndexName.append(value);
        LOGD("TaskSequential::parseAttribute index %s", mIndexName.string());
        return true;
    } else {
        return false;
    }
}