#ifndef ROW_HPP
#define ROW_HPP
#include "sorting_algorithms.hpp"
#include <iostream>
#include <cstdint>
#include <utility>

using namespace std;
template <typename T>
class Row;

template <typename T>
class Row {
	private:
		T* p;
		uint32_t n;


	public:
		//constructor
		Row(uint32_t size=0){
			n=size;
			if(n>0){
				p = new T[n];
				}
			else{
				p = nullptr;
				}
		}


		

		//destuctor
		~Row(){
			delete[] p;
		}




		//copy constractor
		Row(const Row &other){
			n=other.n;

			if (n>0){
				p=new  T[n];
				for (uint32_t i=0; i<n; i++){
					p[i]=other.p[i];
					}
				}
			else{
				p = nullptr;

				}
		}



		//assignment operator(deep copy)
		Row& operator=(const Row& other){
			if (this == other){
			return *this;
			}

			delete[] p;

			n=other.n;
			if (n>0){
				p=new T[n];
				for (uint32_t i=0; i<n; i++){
					p[i]=other.p[i];
				}
			}
			else{
				p=nullptr;
				}

		return *this;
		}

		//operator[]
		T& operator[](uint32_t idx){
			return p[idx];
			
		}

		const T& operator[](uint32_t idx) const{
			return p[idx];
			
		}

		//operator at
		T& at(uint32_t idx){
			if (idx >= n){
				throw out_of_range("εκτος οριων");
				}
			return p[idx];
		}

		const T& at(uint32_t idx) const{
			if (idx >= n){
				throw out_of_range("εκτος οριων");
				}
			return p[idx];
		}

		//ostream operator
		friend ostream& operator <<(ostream& os,const Row<T>& r){
			for(uint32_t i=0; i<r.n; i++){
				os << r.p[i];
				if (i<r.n-1){
					os <<" ";
					}
				}
			return os;
		}


		//istream operator
		friend istream& operator <<(istream& is, Row<T>& r){
			for (uint32_t i=0; i< r.n; i++){
				is >> r.p[i];
				}
			return is;
		}

};


#endif
