#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;

namespace Biolab{
	class DNA_Strand{
		private:
			char* genes;
			int length;
		public:
			DNA_Strand(int len=0){
				length=len;
				if(length>0){
					genes=new char[length];
					for(int i=0;i<length;i++){
						genes[i]='-';
					}
				} else {
					genes=nullptr;
				}
			}
			~DNA_Strand(){delete[] genes;}
			DNA_Strand(const DNA_Strand& other){
				length=other.length;
				genes=new char[length];
				for(int i=0;i<length;i++){
					genes[i]=other.genes[i];
				}
			}
			DNA_Strand& operator=(const DNA_Strand& other){
				if(this==&other) return *this;
				delete[] genes;
				length=other.length;
				genes=new char[length];
				for(int i=0;i<length;i++){
					genes[i]=other.genes[i];
				}
				return *this;
			}
			char& operator[](int index){return genes[index];}
			const char& operator[](int index) const{return genes[index];}
			char& at(int index){
				if(index<0||index>=length){
					throw out_of_range("CRITICAL WARNING: Out of bounds!");
				}
				return genes[index];
			}
			const char& at(int index) const{
				if(index<0||index>=length) throw out_of_range("Out of bounds!");
				return genes[index];
			}
			friend ostream& operator<<(ostream& os,const DNA_Strand& obj){
				if(obj.length==0){
					os<<"[EMPTY SAMPLE]";
					return os;
				}
				os<<"5' -[";
				for(int i=0;i<obj.length;i++){
					os<<obj.genes[i]<<" ";
				}
				os<<"]- 3' (Length: "<<obj.length<<")";
				return os;
			}
			friend istream& operator>>(istream& is,DNA_Strand& obj){
				string inputSequence;
				is>>inputSequence;
				delete[] obj.genes;
				obj.length=inputSequence.length();
				obj.genes=new char[obj.length];
				for(int i=0;i<obj.length;i++){
					obj.genes[i]=toupper(inputSequence[i]);
				}
				return is;
			}
			int getLength() const{return length;}
	};
}

using namespace Biolab;

int main(){
	cout<<"\n========================================================="<<endl;
	cout<<"       [***] CRISPR BOI-HACKER SIMULATOR v2.0 [***]      "<<endl;
	cout<<"=========================================================\n"<<endl;
	DNA_Strand patientDNA;
	bool systemActive=true;
	while (systemActive){
		cout<<"\n------------------------------------------------"<<endl;
		cout<<" [CURRENT DNA SAMPLE]:\n"<<patientDNA<<endl;
		cout<<"------------------------------------------------"<<endl;
		cout<<" CHOICES:"<<endl;
		cout<<" 1. Insert new sample"<<endl;
		cout<<" 2. Safe DNA check"<<endl;
		cout<<" 3. Experimental DNA check"<<endl;
		cout<<" 4. Close system"<<endl;
		cout<<"----------------------------------------------------"<<endl;
		cout<<"> Answer: ";
		int choice;
		cin>>choice;
		switch(choice){
			case 1:{
				cout<<"\n[>] Insert the new sequence: ";
				cin>>patientDNA;
				cout<<"[+] DNA stored successfully!"<<endl;
				break;
			}
			case 2:{
				if(patientDNA.getLength()==0){
					cout<<"[-] There is no sample."<<endl;
					break;
				}
				int pos;
				char newGene;
				cout<<"\n[>] Give position (Index 0 to "<<patientDNA.getLength()-1<<") for mutation: ";
				cin>>pos;
				cout<<"[>] Give new gene(A, C, G or T): ";
				cin>>newGene;
				try{
					patientDNA.at(pos)=toupper(newGene);
					cout<<"[+] The safe mutation has been completed!"<<endl;
				}
				catch(const out_of_range& e){
					cout<<"\n[!!!] SAMPLE DESTRUCTION PREVENTION [!!!]"<<endl;
					cout<<"[ERROR]: "<<e.what()<<endl;
				}
				break;
			}
			case 3:{
				if(patientDNA.getLength()==0){
					cout<<"[-] There is no sample."<<endl;
					break;
				}
				int pos;
				char newGene;
				cout<<"\n[!] WARNING: You are in experimental mode [!]"<<endl;
				cout<<"[>] Give position for mutation: ";
				cin>>pos;
				cout<<"[>] Give new gene (A, C, G or T): ";
				cin>>newGene;
				patientDNA[pos]=toupper(newGene);
				cout<<"[?] The mutation was executed blindly.. We hope you hit the DNA and not the core of the O.S.!"<<endl;
				break;
			}
			case 4:{
				cout<<"\n[>] Deactivating system..."<<endl;
				systemActive=false;
				break;
			}
			default:
				cout<<"[-] Invalid choice."<<endl;
				break;
		}
	}
	return 0;
}
