#include <iostream.h>
#include "list.h"

class int_node: public node {
  int data;
};

void dump(const dll<int> &L) {
  assert(L.Check());
  for(dllConstP<int> i(L); i.valid(); i.inc())
    cout<<" "<<*i;
  cout<<" (len="<<L.len()<<")\n";
}

main() {
  // random instantiations
  list<int> *lp;
  List<int> *Lp;
    
  listP<int> *lPp;
  ListP<int> *LPp;
  
  node n;
  dll<int> L;
  dllP<int> LP(L);
  dllConstP<int> CLP(L);


  

  L.ins_head(10);
  L.ins_tail(11);
  for(int i=0; i<10; i++)
    L.ins(L.len()/2, 12+i);

  cout<<"insert check test...";
  L.ins(L.len(), 100);

  cout<<"*** printing list: ***\n";
  dump(L);


  // systematic instantiations

  // default ctor already done

  dll<int> L1(L);
  cout<<"copy ctor: "; dump(L1);

  const dll<int> L2(L1);
  dll<int> L3(L2);
  cout<<"L2: "; dump(L2);
  cout<<"L3: "; dump(L3);

  dll<int> L4;
  for(int i=1; i<10000; i*=3)
    L4.ins_head(i);
  cout<<"L4: "; dump(L4);
  L3= L4; cout<<"L3=L4: "; dump(L3);


  // len already exercised
  // empty:
  dll<int> L5;
  cout<<"L5: "; dump(L5);
  dll<int> L6(L5); L6.ins_tail(444);
  cout<<"L6: "; dump(L6);
  cout<<"L4.empty()="<<L4.empty()<<"; L5.empty="<<L5.empty()<<"\n";

  // index()
  for(int i=0; i<L1.len(); i++) {
    cout<<i<<": ";
    cout<<" "<<L1.Index(i);
    cout<<" "<<L1[i];
    cout<<" "<<L2.cIndex(i);
    cout<<" "<<L2[i];
    cout<<"\n";
  }
  L1.Index(4)=42;
  L1[5]=69;
  cout<<"modified L1[4,5]:\n";
  for(int i=0; i<L1.len(); i++) {
    cout<<i<<": ";
    cout<<" "<<L1.Index(i);
    cout<<" "<<L1[i];
    cout<<" "<<L2.cIndex(i);
    cout<<" "<<L2[i];
    cout<<"\n";
  }

  // del, del_head, del_tail
  L1.del(9); L3.del_head(); L4.del_tail();
  cout<<"deleted from L1, L3, L4\n";
  cout<<"L1: "; dump(L1);
  cout<<"L2: "; dump(L2);
  cout<<"L3: "; dump(L3);
  cout<<"L4: "; dump(L4);

  // ins, ins_head, ins_tail
  L1.ins(2,666); L3.ins_head(666); L4.ins_tail(666);
  cout<<"inserted 666 to L1, L3, L4\n";
  cout<<"L1: "; dump(L1);
  cout<<"L2: "; dump(L2);
  cout<<"L3: "; dump(L3);
  cout<<"L4: "; dump(L4);

  // get, pop_head, pop_tail
  int a,b,c,d,e,f;
  L1.get(11,a); L3.pop_head(b); L4.pop_tail(c);
  cout<<"popped/got element from L1, L3, L4:"<<a<<" "<<b<<" "<<c<<"\n";
  cout<<"L1: "; dump(L1);
  cout<<"L2: "; dump(L2);
  cout<<"L3: "; dump(L3);
  cout<<"L4: "; dump(L4);

  // head, tail
  a= L1.head(); b=L1.tail(); c=L2.head(); d=L2.tail();
  cout<<"got head,tail from L1,L2: "<<a<<" "<<b<<" "<<c<<" "<<d<<"\n";

  // headP, tailP, elemP (const/nonconst)
  dllConstP<int> A,B,C,D,E,F;
  A=L2.headP();
  B=L2.tailP();
  C=L2.elemP(4);
  D=L3.headP();
  E=L3.tailP();
  F=L3.elemP(4);
  cout<<"got headP,tailP,elemP(4) from L2,L3: ";
  A.Check();B.Check();C.Check();
  D.Check();E.Check();F.Check();
  cout<<*A<<" "<<*B<<" "<<*C<<" "<<*D<<" "<<*E<<" "<<*F<<"\n";

  dllP<int> *pp,*qq;
  dllConstP<int> *rr,*ss;
  pp= L1.new_iter();
  qq= L3.new_iter();
  rr= L2.new_const_iter();
  ss= L3.new_const_iter();
  cout<<"allocated pp,qq,rr,ss using new_iter,new_const_iter...";
  pp->Check(); qq->Check(); rr->Check(); ss->Check();
  cout<<"check complete\n";
  delete pp; delete qq; delete rr; delete ss;


  // exercising dllP and dllConstP

  // ctors:
  cout<<"****** take 1: dllP:\n";
  dllP<int> X; // default ctor
  dllP<int> Y(L1); // construct from list (head)
  dllP<int> Z(X),W(Y); // copy ctor
  cout<<"*** verify X ***\n"; assert(!X.initialized());
  cout<<"*** verify Y ***\n"; assert(Y.Check());
  cout<<"*** verify Z ***\n"; assert(!Z.initialized());
  cout<<"*** verify W ***\n"; assert(W.Check());

  // go,go_head,go_tail
  cout<<"go_head, go_tail: X.go_head(L3),Z.go_tail(L4),Y.go_head(),W.go_tail():\n";
  X.go_head(L3);
  Z.go_tail(L4);
  Y.go_head();
  W.go_tail();
  cout<<"X:"<<*X<<" Z:"<<*Z<<" Y:"<<*Y<<" W:"<<*W<<"\n";

  cout<<"go: X.go(3), Y.go(L6,0)\n";
  X.go(3);
  Y.go(L6,0);
  cout<<"X:"<<*X<<" Y:"<<*Y<<"\n";

  // dereference
  cout<<"Y.go_tail(L3)\n";
  Y.go_tail(L3);
  cout<<"X, Y .Data .cData .operator*:\n";
  cout<<X.Data()<<" "<<X.cData()<<" "<<*X<<"\n";
  cout<<Y.Data()<<" "<<Y.cData()<<" "<<*Y<<"\n";

  // ind_fwd, ins_back, del_fwd, del_back
  cout<<"L3: "; dump(L3);
  cout<<"X.ins_fwd(777), Y.ins_back(888)\n";
  X.ins_fwd(777); assert(X.Check());
  Y.ins_back(888); assert(Y.Check());
  cout<<"X:"<<*X<<" Y:"<<*Y<<"\n";
  cout<<"L3: "; dump(L3);
  cout<<"X.del_back(), Y.del_fwd()\n";
  X.del_back();
  assert(X.Check());
  Y.del_fwd();
  assert(Y.Check());
  cout<<"L3: "; dump(L3);
  cout<<"X:"<<*X<<" Y.valid():"<<Y.valid()<<"\n";

  // get_fwd, get_back
  int xxx;
  X.get_fwd(xxx);
  cout<<"X.get_fwd(): "<<xxx<<"\n";
  cout<<"L3: "; dump(L3);
  X.get_back(xxx);
  cout<<"X.get_back(): "<<xxx<<"\n";
  cout<<"L3: "; dump(L3);

  // inc, dec, ++, --
  cout<<"X:"<<*X<<"\n";
  X.inc();
  cout<<"X.inc(); X:"<<*X<<"\n";
  cout<<"++X="<<*(++X)<<"\n";
  cout<<"X++="<<*(X++)<<"\n";
  cout<<"X:"<<*X<<"\n";

  X.dec();
  cout<<"X.dec(); X:"<<*X<<"\n";
  cout<<"--X="<<*(--X)<<"\n";
  cout<<"X--="<<*(X--)<<"\n";
  cout<<"X:"<<*X<<"\n";

  // ==,!=
  cout<<"\n==, != :\n";
  Y=X;
  cout<<"Y=X: *X="<<*X<<" *Y="<<*Y<<" X==Y:"<<(X==Y)<<" X!=Y:"<<(X!=Y)<<"\n";
  Y++;
  cout<<"Y++: *Y="<<*Y<<" X==Y:"<<(X==Y)<<" X!=Y:"<<(X!=Y)<<"\n";
  X++;
  cout<<"X++: *X="<<*X<<" X==Y:"<<(X==Y)<<" X!=Y:"<<(X!=Y)<<"\n";

  // at_head(), at_tail()
  cout<<"\nat_head, at_tail\n";
  while(X.valid()) {
    cout<<"*X="<<*X<<" at_head="<<X.at_head()<<" at_tail="<<X.at_tail();
    X++; cout<<";  X++\n";
  }
  while(Y.valid()) {
    cout<<"*Y="<<*Y<<" at_head="<<Y.at_head()<<" at_tail="<<Y.at_tail();
    Y--; cout<<";  Y--\n";
  }

  // GetList(), cGetList
  cout<<"\nGetList, cGetList\n";
  cout<<"X.GetList()="; dump(X.GetList());
  cout<<"X.cGetList()="; dump(X.cGetList());


  cout<<"\n";

  cout<<"****** take 2: dllConstP:\n";
  dllConstP<int> cX; // default ctor
  dllConstP<int> cY(L2); // construct from list (head)
  dllConstP<int> cZ(cY),cW(Y); // copy ctor
  cout<<"*** verify cX ***\n"; assert(!cX.initialized());
  cout<<"*** verify cY ***\n"; assert(cY.Check()); dump(cY.cGetList());
  cout<<"*** verify cZ ***\n"; assert(cZ.Check()); dump(cZ.cGetList());
  cout<<"*** verify cW ***\n"; assert(cW.Check()); dump(cW.cGetList());

  cout<<"*** verify L *****\n";
  assert(L.Check()); dump(L);
  cout<<"*** verify L1 ****\n";
  assert(L1.Check()); dump(L1);
  cout<<"*** verify L2 ****\n";
  assert(L2.Check()); dump(L2);
  cout<<"*** verify L3 ****\n";
  assert(L3.Check()); dump(L3);
  cout<<"*** verify L4 ****\n";
  assert(L4.Check()); dump(L4);
  cout<<"*** verify L5 ****\n";
  assert(L5.Check()); dump(L5);
  cout<<"*** verify L6 ****\n";
  assert(L6.Check()); dump(L6);

  cout<<"\n";

 
  // go,go_head,go_tail
  cout<<"go_head, go_tail: cX.go_head(L3),cZ.go_tail(L4),cY.go_head(),cW.go_tail():\n";
  cX.go_head(L3);
  cZ.go_tail(L4);
  cY.go_head();
  cW.go_tail();
  cout<<"cX:"<<*cX<<" cZ:"<<*cZ<<" cY:"<<*cY<<" cW:"<<*cW<<"\n";

  cout<<"go: cX.go(2), cY.go(L6,0)\n";
  cX.go(2);
  cY.go(L6,0);
  cout<<"cX:"<<*cX<<" cY:"<<*cY<<"\n";

  // dereference
  cout<<"Y.go_tail(L3)\n";
  Y.go_tail(L3);
  cout<<"cX, cY .cData .operator*:\n";
  cout<<cX.cData()<<" "<<*cX<<"\n";
  cout<<cY.cData()<<" "<<*cY<<"\n";

  // inc, dec, ++, --
  cout<<"cX:"<<*cX<<"\n";
  cX.inc();
  cout<<"cX.inc(); cX:"<<*cX<<"\n";
  cout<<"++cX="<<*(++cX)<<"\n";
  cout<<"cX++="<<*(cX++)<<"\n";
  cout<<"cX:"<<*cX<<"\n";

  cX.dec();
  cout<<"cX.dec(); cX:"<<*cX<<"\n";
  cout<<"--cX="<<*(--cX)<<"\n";
  cout<<"cX--="<<*(cX--)<<"\n";
  cout<<"cX:"<<*cX<<"\n";

  // ==,!=
  cout<<"\n==, != :\n";
  cY=cX;
  cout<<"cY=cX: *cX="<<*cX<<" *cY="<<*cY<<" cX==cY:"<<(cX==cY)<<" cX!=cY:"<<(cX!=cY)<<"\n";
  cY++;
  cout<<"cY++: *cY="<<*cY<<" cX==cY:"<<(cX==cY)<<" cX!=cY:"<<(cX!=cY)<<"\n";
  cX++;
  cout<<"cX++: *cX="<<*cX<<" cX==cY:"<<(cX==cY)<<" cX!=cY:"<<(cX!=cY)<<"\n";

  // at_head(), at_tail()
  cout<<"\nat_head, at_tail\n";
  while(cX.valid()) {
    cout<<"*cX="<<*cX<<" at_head="<<cX.at_head()<<" at_tail="<<cX.at_tail();
    cX++; cout<<";  cX++\n";
  }
  while(cY.valid()) {
    cout<<"*cY="<<*cY<<" at_head="<<cY.at_head()<<" at_tail="<<cY.at_tail();
    cY--; cout<<";  cY--\n";
  }

  // GetList(), cGetList
  cout<<"\ncGetList\n";
  cout<<"cX.cGetList()="; dump(cX.cGetList());


  // dllP <<>> dllConstP
  cout<<"\ndllP <<>> dllConstP\n";
  cX=X;
  cout<<"X=cX; X==cX:"<<(X==cX)<<" X!=cX:"<<(X!=cX)<<"\n";
  cout<<"cX==X:"<<(cX==X)<<" cX!=X:"<<(cX!=X)<<"\n";


  // test clear()
  cout<<"\nclear() -- delete list\n";
  cout<<"L1: "; dump(L1);
  L1.clear(); cout<<"L1.clear() --\n";
  cout<<"L1: "; dump(L1);


  cout<<"\n";

  cout<<"*** verify L *****\n";
  assert(L.Check()); dump(L);
  cout<<"*** verify L1 ****\n";
  assert(L1.Check()); dump(L1);
  cout<<"*** verify L2 ****\n";
  assert(L2.Check()); dump(L2);
  cout<<"*** verify L3 ****\n";
  assert(L3.Check()); dump(L3);
  cout<<"*** verify L4 ****\n";
  assert(L4.Check()); dump(L4);
  cout<<"*** verify L5 ****\n";
  assert(L5.Check()); dump(L5);
  cout<<"*** verify L6 ****\n";
  assert(L6.Check()); dump(L6);
  cout<<"*** verify LP ****\n";
  assert(LP.Check());
  cout<<"*** verify CLP ***\n";
  assert(CLP.Check());
  
  cout<<"\n\n****** ran successfully ******\n";
}
