// 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.

// Date: Sun Sep 20 12:25:11 CST 2015

#ifndef  BVAR_VECTOR_H
#define  BVAR_VECTOR_H

#include <ostream>
#include <gflags/gflags_declare.h>

namespace bvar {

DECLARE_bool(quote_vector);

// Data inside a Vector will be plotted in a same graph.
template <typename T, size_t N>
class Vector {
public:
    static const size_t WIDTH = N;

    Vector() {
        for (size_t i = 0; i < N; ++i) {
            _data[i] = T();
        }
    }
    
    Vector(const T& initial_value) {
        for (size_t i = 0; i < N; ++i) {
            _data[i] = initial_value;
        }
    }
    
    void operator+=(const Vector& rhs) {
        for (size_t i = 0; i < N; ++i) {
            _data[i] += rhs._data[i];
        }
    }
    
    void operator-=(const Vector& rhs) {
        for (size_t i = 0; i < N; ++i) {
            _data[i] -= rhs._data[i];
        }
    }

    template <typename S>
    void operator*=(const S& scalar) {
        for (size_t i = 0; i < N; ++i) {
            _data[i] *= scalar;
        }
    }

    template <typename S>
    void operator/=(const S& scalar) {
        for (size_t i = 0; i < N; ++i) {
            _data[i] /= scalar;
        }
    }

    bool operator==(const Vector& rhs) const {
        for (size_t i = 0; i < N; ++i) {
            if (!(_data[i] == rhs._data[i])) {
                return false;
            }
        }
        return true;
    }

    bool operator!=(const Vector& rhs) const {
        return !operator==(rhs);
    }
    
    T& operator[](int index) { return _data[index]; }
    const T& operator[](int index) const { return _data[index]; }

private:
    T _data[N];
};

template <typename T, size_t N>
std::ostream& operator<<(std::ostream& os, const Vector<T, N>& vec) {
    if (FLAGS_quote_vector) {
        os << '"';
    }
    os << '[';
    if (N != 0) {
        os << vec[0];
        for (size_t i = 1; i < N; ++i) {
            os << ',' << vec[i];
        }
    }
    os << ']';
    if (FLAGS_quote_vector) {
        os << '"';
    }
    return os;
}

template <typename T>
struct is_vector : public butil::false_type {};

template <typename T, size_t N>
struct is_vector<Vector<T,N> > : public butil::true_type {};

}  // namespace bvar

#endif  //BVAR_VECTOR_H
