#ifndef ROW_HPP
#define ROW_HPP

#include <iostream>
#include "sort_algorithms.hpp"
#include <cstdint>
#include <stdexcept>
template <typename T>
class row{
	private: 
		T* p;
		uint32_t n;

	public:
		//Constructor
		row() {
			p = nullptr;
			n=0;
		}

		row(T* newP,uint32_t newN) {
			n=newN;
			p= new T[n];

			for (uint32_t i=0; i<n; i++){
				p[i]= newP[i];
			}
		}
		//Destructor
		~row() {
			delete[] p;
		}
		//Copy Constructor
		row(const row& obj) {
			n=obj.n;
			p=new T[n];

			for (uint32_t i=0; i<n; i++){
				p[i]=obj.p[i];
			}
		}
		//Deep copy
		row& operator=(const row& other){
			if (this!=&other){
				delete[] p;

				n=other.n;
				p=new T[n];

				for (uint32_t i=0; i<n; i++){
					p[i]=other.p[i];
				}
			}

			return *this;
		}
		//Operator []
		T& operator[](uint32_t index){
			return p[index];
		}
		T& at(uint32_t index){
			if (index>=n){
				throw std::out_of_range("Εκτός ορίων");
				}
			return p[index];
			}
		
				
		uint32_t size() const{
			return n;
		}	

		template <typename U>
		friend std::ostream& operator<<(std::ostream& os, const row<U>& obj)
		{
			os << "[";
			for (uint32_t i=0; i<obj.n; i++){
				os<<obj.p[i];
				if(i<obj.n-1){
					os<<",";
				}
			}
			os << "]";
			return os;

		}

		template <typename U>
		friend std::istream& operator>>(std::istream& is, row<U>& obj){
			for (uint32_t i=0; i<obj.n; i++) {
				is>>obj.p[i];
			}
			return is;
		}
		
};	
#endif
