#ifndef _ct_vector_h_
#define _ct_vector_h_
#include <cstddef> // For size_t
#include <stdexcept> // For exceptions

namespace ct
{
template <typename T>
class Vector {
public:
    using value_type = T;
    using size_type = std::size_t;
    using iterator = T*;
    using const_iterator = const T*;

    // Constructors
    Vector() noexcept;
    explicit Vector(size_type count);
    Vector(size_type count, const T& value);
    Vector(std::initializer_list<T> list);
    Vector(const Vector& other);
    Vector(Vector&& other) noexcept;
    ~Vector();

    // Assignment operators
    Vector& operator=(const Vector& other);
    Vector& operator=(Vector&& other) noexcept;
    Vector& operator=(std::initializer_list<T> list);
    //specially added for CT 301 
    Vector& operator+=(const Vector& other);
    Vector operator+(const Vector& other) const;
    Vector& operator-=(const Vector& other);
    Vector operator-(const Vector& other) const;
    
    friend Vector<T> operator+(const Vector<T>& lhs, const Vector<T>& rhs); 
    friend Vector<T> operator-(const Vector<T> &lhs, const Vector<T>& rhs);
    friend bool operator==(const Vector<T> &lhs, const Vector<T>& rhs);
    friend bool operator!=(const Vector<T> &lhs, const Vector<T>& rhs);
    friend Vector<T> set_union(const Vector<T> &lhs, const Vector<T>& rhs);
    friend Vector<T> set_difference(const Vector<T> &lhs, const Vector<T>& rhs);
    friend Vector<T> set_intersection(const Vector<T> &lhs, const Vector<T>& rhs);
    friend Vector<T> set_symmetric_difference(const Vector<T> &lhs, const Vector<T>& rhs);

    bool set_isdisjoint(const Vector<T>& other); 
    bool set_issubset(const Vector<T>& other); 
    // Element access
    T& at(size_type pos);
    const T& at(size_type pos) const;
    T& operator[](size_type pos);
    const T& operator[](size_type pos) const;
    T& front();
    const T& front() const;
    T& back();
    const T& back() const;
    T* data() noexcept;
    const T* data() const noexcept;

    // Iterators
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;

    // Capacity
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type capacity() const noexcept;
    void reserve(size_type new_cap);
    void shrink_to_fit();

    // Modifiers
    void clear() noexcept;
    iterator insert(const_iterator pos, const T& value);
    iterator insert(const_iterator pos, T&& value);
    iterator insert(const_iterator pos, size_type count, const T& value);
    template<class InputIt>
    iterator insert(const_iterator pos, InputIt first, InputIt last);
    iterator erase(const_iterator pos);
    iterator erase(const_iterator first, const_iterator last);
    void push_back(const T& value);
    void push_back(T&& value);
    void pop_back();
    void resize(size_type count);
    void resize(size_type count, const T& value);
    void swap(Vector& other) noexcept;

private:
    T* elements;
    size_type currentSize;
    size_type currentCapacity;

    void allocate(size_type new_capacity);
    void deallocate();
};

}//end of namespace 

#endif 