#include<iostream>
#include<stdarg.h>
#include<fstream>
using namespace std;

class Table{
 protected:
   int n,m;
   int *high,*wide;
 public:
   static int count;
   Table(int m1,int n1,int *h,int *w);
   Table(const Table &t);
// edit
   virtual ~Table();
   Table &operator=(const Table &t);
   bool operator==(const Table &t)const;
   friend ostream &operator<<(ostream &st,const Table &t);
   void AddCol(int w); //to the end
   void SubCol();//from the end
   void AddRow(int h);//to the bottom
   void SubRow();//from the bottom
   void ChangeWide(int col, int w);//col-number of col, w-wide
   void ChangeHigh(int row, int h);//row-number of row, h-high
   virtual void print(char c1,char c_)const;
};

// edit
int Table::count = 0;

template<class Type>
class Table_1:public Table{
 protected:
   Type *data;
 public:
   Table_1(int m1,int n1,int *h,int *w);
   Table_1(const Table_1 &t);
   ~Table_1();
   Table_1 &operator=(const Table_1 &t);
   bool operator==(const Table_1 &t)const;
   friend ostream &operator<<<>(ostream &st,const Table_1 &t);
   void AddCol(int w); //to the end
   void SubCol();//from the end
   void AddRow(int h);//to the bottom
   void SubRow();//from the bottom
   Type *operator[](int row);
   void print(char c1,char c_)const;
};

///////////////////////////////////////////////////////////////////////

Table::Table(int m1,int n1,int *h,int *w){
          if(m1<=0||n1<=0)throw "Irregular table size";
          m=m1;n=n1;
          high=new int[m];
          wide=new int[n];
          for(int i=0;i<m;i++){
                if(h[i]<=0) throw "Wrong table high";
                high[i]=h[i];}
          for(int i=0;i<n;i++){
                if(w[i]<=0) throw "Wrong table wide";
                wide[i]=w[i];}
          count++;
          }

Table::Table(const Table &t){
          n=t.n;m=t.m;
          high=new int[m];
          wide=new int[n];
          for(int i=0;i<m;i++) high[i]=t.high[i];
          for(int i=0;i<n;i++) wide[i]=t.wide[i];
          count++;
          }

Table::~Table(){
          delete [] high;
          delete [] wide;
          count--;
          }

Table& Table::operator=(const Table &t){
          if (this==&t) return *this;
          n=t.n;m=t.m;
          delete [] high;
          delete [] wide;
          high=new int[m];
          wide=new int[n];
          for(int i=0;i<m;i++) high[i]=t.high[i];
          for(int i=0;i<n;i++) wide[i]=t.wide[i];
          return *this;
          }

bool Table::operator==(const Table &t)const{
          if (this==&t) return true;
          if (n!=t.n || m!=t.m) return false;
          else{ for(int i=0;i<n;i++)
                   if (wide[i]!=t.wide[i]) return false;
                for(int i=0;i<m;i++)
                   if (high[i]!=t.high[i]) return false;
                return true;}
          }

ostream &operator<<(ostream &st,const Table &t){
          t.print('|','-');
          return st;
          }

void Table::AddCol(int w){
          if(w<=0) throw "Wrong table wide in adding collom";
          n++;
          int *wp=new int[n];
          for(int i=0;i<n-1;i++) wp[i]=wide[i];
          wp[n-1]=w;
          delete [] wide;
          wide=wp;
          }

void Table::SubCol(){
          n--;
          int *wp=new int[n];
          for(int i=0;i<n;i++) wp[i]=wide[i];
          delete [] wide;
          wide=wp;
          }

void Table::AddRow(int h){
          if(h<=0) throw "Wrong table high in adding row";
          m++;
          int *hp=new int[m];
          for(int i=0;i<m-1;i++) hp[i]=high[i];
          hp[m-1]=h;
          delete [] high;
          high=hp;
          }

void Table::SubRow(){
          m--;
          int *hp=new int[m];
          for(int i=0;i<m;i++) hp[i]=high[i];
          delete [] high;
          high=hp;
          }

void Table::ChangeWide(int col, int w){
          if(w<=0) throw "Wrong table wide in changing wide";
          if(col<1 || col>n) throw "Wrong collom in changing wide";
          wide[col-1]=w;
          }

void Table::ChangeHigh(int row, int h){
          if(h<=0) throw "Wrong table high in changing high";
          if(row<1 || row>m) throw "Wrong row in changing high";
          high[row-1]=h;
          }

void Table::print(char c1,char c_)const{
          int len=0;
          for(int i=0;i<n;i++)
              len+=wide[i];
          len+=n+1;
          for(int i=0;i<m;i++){
            for(int j=0;j<len;j++) cout<<c_;
            cout<<endl;
            for(int j=0;j<high[i];j++){
               for(int l=0;l<n;l++){
                  cout<<c1;
                  for(int k=0;k<wide[l];k++) cout<<' ';}
               cout<<c1<<endl;}}
          for(int i=0;i<len;i++) cout<<c_;
          cout<<endl;
          }

///////////////////////////////////////////////////////////////////////

template<class Type>
Table_1<Type>::Table_1(int m1,int n1,int *h,int *w):
          Table(m1,n1,h,w){
          data=new Type[m*n];
          }

template<class Type>
Table_1<Type>::Table_1(const Table_1 &t):
          Table(t){
          data=new Type[m*n];
          for(int i=0;i<n*m;i++) data[i]=t.data[i];
          }

template<class Type>
Table_1<Type>::~Table_1(){
          delete [] data;
          }

template<class Type>
Table_1<Type> & Table_1<Type>::operator= (const Table_1 &t){
          if (this==&t) return *this;
          Table *pb=this;
          *pb=dynamic_cast<Table&>(t);
          delete [] data;
          data=new Type[n*m];
          for(int i=0;i<n*m;i++) data[i]=t.data[i];
          return *this;
          }

template<class Type>
bool Table_1<Type>::operator==(const Table_1 &t)const{
          Table *pb=this;
          if(*pb==dynamic_cast<Table&>(t)){
             for(int i=0;i<n*m;i++)
                if(data[i]!=t.data[i]) return false;
             return true;}
          else return false;
          }

template<class Type>
ostream &operator<<(ostream &st,const Table_1<Type> &t){
          t.print('|','-');
          return st;
          }

template<class Type>
void Table_1<Type>::AddCol(int w){
          Table::AddCol(w);
          Type *d=new Type[n*m];
          int k=1;
          for(int i=0;i<n*m-1;i++){
               if(i==k*n-1){i++;k++;}
               d[i]=data[i-k+1];}
          delete [] data;
          data=d;
          }

template<class Type>
void Table_1<Type>::SubCol(){
          Table::SubCol();
          Type *d=new Type[n*m];
          int k=1;
          for(int i=0;i<n*m;i++){
               if(i==(k+1)*n)k++;
               d[i]=data[i+k-1];}
          delete [] data;
          data=d;
          }

template<class Type>
void Table_1<Type>::AddRow(int h){
          Table::AddRow(h);
          Type *d=new Type[n*m];
          for(int i=0;i<n*(m-1);i++) d[i]=data[i];
          delete [] data;
          data=d;
          }

template<class Type>
void Table_1<Type>::SubRow(){
          Table::SubRow();
          Type *d=new Type[n*m];
          for(int i=0;i<n*m;i++) d[i]=data[i];
          delete [] data;
          data=d;
          }

template<class Type>
Type *Table_1<Type>::operator[](int row){
          if(row<1||row>m) throw "Wrong table size in changing data";
          return data+(row-1)*n;
          }

/*void Table::print(char c1,char c_)const{
          int len=0;
          for(int i=0;i<n;i++)
              len+=wide[i];
          len+=n+1;
          for(int i=0;i<m;i++){
            for(int j=0;j<len;j++) cout<<c_;
            cout<<endl;
            for(int j=0;j<high[i];j++){
               for(int l=0;l<n;l++){
                  cout<<c1;
                  for(int k=0;k<wide[l];k++) cout<<' ';}
               cout<<c1<<endl;}}
          for(int i=0;i<len;i++) cout<<c_;
          cout<<endl;
          }*/

// edit
template<class Type>
void Table_1<Type>::print (char c1,char c_)const{
          char c;
          char **str;
          int len=0;
          for(int i=0;i<n;i++)
              len+=wide[i];
          len+=n+1;
          for(int i=0;i<m;i++){
            for(int j=0;j<len;j++) cout<<c_;
            cout<<endl;
            str=new char *[n*high[i]];
            for(int j=0;j<n;j++){
                 for(int l=0;l<high[i];l++){
                       str[j*high[i]+l]=new char[wide[j]+1];
                       for(int k=0;k<wide[j];k++) str[j*high[i]+l][k]=' ';
                       str[j*high[i]+l][wide[j]]='\0';}
                 ofstream myofstream("file");
                 if(!myofstream.is_open()) throw "Can't open file";
                 myofstream<<data[ni+j];
                 myofstream.close();
                 ifstream myifstream("file");
                 if(!myifstream.is_open()) throw "Can't open file";
                 for(int k=0;k<high[i];k++){
                       if(myifstream.eof()) break;
                       for(int l=0;l<wide[j];l++){
                                 myifstream>>c;
                                 if(c=='\n' || myifstream.eof()) break;
                                 str[j*high[i]+k][l]=c;}}
                 myifstream.close();}
            for(int j=0;j<high[i];j++){
               for(int l=0;l<n;l++){
                  cout<<c1;
                  cout<<str[l*high[i]+j];}
               cout<<c1<<endl;}}
          for(int i=0;i<len;i++) cout<<c_;
          cout<<endl;
          }


int *func(int n,...){
   int *arr=new int[n];
   va_list ap;
   va_start(ap,n);
   for(int i=0;i<n;i++) arr[i]=va_arg(ap,int);
   return arr;
}

int main(){
   Table t(2,3,func(2,4,4),func(3,3,12,12));
   t.print('|','-');
   return 0;
}
