//
// ************************************************
//
//      Gregg L. Zepp II
//
//      Intro to Java Programming
//
//      Creates a class that uses a 40-element array 
//      of digits to store integers as large as 40
//      digits. Using predicate methods, it tests 
//      the relationship between the objects.
//
//      HW #4, Exercise 8.18 P. 414
//
// ************************************************
//
public class HugeInteger // creates HugeInteger class 
{
    
   public int[] nr;
   public int length;
   public int sign;				
   
   public HugeInteger(int[] n, int l, int s) 
   {
      nr=n;
      length=l;
      sign=s;
   }
   
   public static void main(String[] args) 
   {
      
      HugeInteger left = new HugeInteger ("12345678910111234567891011999");
      HugeInteger right = new HugeInteger ("12345678910111234567891011");
      HugeInteger result;
      
      result=left.subtractHugeIntegers(right);
      System.out.print("\n\nLeft  :");left.outputHugeInteger();
      System.out.print("Right :");right.outputHugeInteger();
      System.out.print("===========================================\n");
      System.out.print("Result:");result.outputHugeInteger();
      
      boolean isGreater = left.isGreaterThan(right);

      System.out.printf("\nRelationship between the objects held? %b\n\n\n",isGreater);
   }
   
   public HugeInteger inputHugeInteger(String s) 
   {
      int t;
      int index;

      index = 0;
      t=s.charAt(index++);
      if (t=='+'||t=='-') 
      {
         if (t=='+') sign=1; else sign=-1;
         t=s.charAt(index++);
      } else sign=1;
      
      do 
      {
         if (((t<'0')|(t>'9'))) 
         {
            System.out.println("Error!\n");
         }
         nr[length++]=(t-'0');
         if (index<s.length()) t=s.charAt(index++); else index++; 
      }
      
      while  (index<=s.length());
      reverse();
      return this;
   }
   
   public HugeInteger outputHugeInteger() 
   {
      if (isZero()) 
      {
         System.out.println("0\n");
         return this;
      }
      if (sign==-1) System.out.print("-");
      for (int i=length-1;i>-1;i--) 
         System.out.print(nr[i]);
      System.out.println();
      return this;
   }
   
   public void setTo(HugeInteger c) 
   {
      nr=c.nr;
      length=c.length;
      sign=c.sign;
   }
   
   private HugeInteger addOne() 
   {
      HugeInteger tmp;
      tmp = new HugeInteger();
      tmp.nr[0]=1;
      tmp.length=0;
      return addHugeIntegers(tmp);
   }
   
   public HugeInteger addHugeIntegers(HugeInteger add) 
   {
      int[] tmp;
      int ltmp;
      int stmp;
      int carry;
      
      carry=0;stmp=1;tmp=new int[40];ltmp=0;
      for (int i=0;i<40;i++) 
      {
         tmp[i]=nr[i]*sign+add.nr[i]*add.sign+carry;
         if (tmp[i]>9) 
         {
            carry=(int)(tmp[i]/10);
            tmp[i]=tmp[i]-carry*10;
         } else
         if (tmp[i]<-9) 
         {
            carry=(int)(tmp[i]/10);
            tmp[i]=tmp[i]-carry*10;
         } else carry=0;
      }
      
      for (int i=39;i>=0;i--) 
         if (tmp[i]!=0) 
         {
            ltmp=i+1;
            break;
         }
      if (tmp[ltmp-1]<0) 
      {
         stmp=-1;
         for (int i=0;i<ltmp;i++) 
         {
            tmp[i]=-tmp[i];
         }
         
      }
         
      for (int i=0;i<ltmp;i++) 
         {
               if (tmp[i]<0) 
               {
               tmp[i]+=10;
               tmp[i+1]-=1;
               }
         }
         
      return new HugeInteger(tmp,ltmp,stmp);
      
   }
   
   public HugeInteger subtractHugeIntegers(HugeInteger sub) 
   {
      HugeInteger tmp;
      sub.sign*=-1;
      tmp=this.addHugeIntegers(sub);
      sub.sign*=-1;
      return tmp;
   }
   
//   public HugeInteger multiplyHugeIntegers(HugeInteger mult) 
//   {
//        int [] ntmp;
//        int ltmp;
//        int stmp;
//        int carry;
//        
//        stmp=sign*mult.sign;
//        
//        ntmp=new int[40];
//        ltmp=0;
//        
//        for (int j=0;j<mult.length;j++) 
//         {
//         carry=0;
//         for (int i=0;i<40-j;i++) {
//            ntmp[i+j]+=nr[i]*mult.nr[j]+carry;
//            carry=(int)(ntmp[i+j]/10);
//            ntmp[i+j]-=carry*10;
//         }
//            
//        }
//        
//         for (int i=39;i>=0;i--) 
//         if (ntmp[i]!=0) 
//         {
//            ltmp=i+1;
//               break;
//         }
//        
//        return new HugeInteger(ntmp,ltmp,stmp);
//        
//   }
//   
//   public HugeInteger divideHugeIntegers(HugeInteger div) 
//   {
//      HugeInteger a;
//      int stemp,s1,s2;
//      
//      stemp=sign*div.sign;
//      s1=sign;
//      s2=div.sign;
//      sign=1;div.sign=1;
//      
//      a=interval(div);
//      a.sign=stemp;
//      return a;
//   }
//   
//   private HugeInteger divideByTwo() 
//   {
//      int ntmp[];
//      int ltmp;
//      int carry;
//      
//      carry=0;ltmp=0;ntmp=new int[40];
//      for (int i=39;i>=0;i--) 
//      {
//         ntmp[i]=(int)((nr[i]+carry*10)/2);
//         if ((ntmp[i]*2)!=(nr[i]+carry*10)) carry=1; else carry=0;
//      }
//        for (int i=39;i>=0;i--) 
//         if (ntmp[i]!=0) 
//         {
//            ltmp=i+1;
//               break;  
//      }
//      if (ltmp==0) ltmp=1;
//      return new HugeInteger(ntmp,ltmp,sign);
//   }

	public HugeInteger() 
   {
		nr=new int[40];
		for (int i=0;i<40;i++) nr[i]=0;
		length=0;
		sign=+1;
	}
	
	public HugeInteger(String intt) 
   {
		nr=new int[40];
		for (int i=0;i<40;i++) nr[i]=0;
		length=0;
		sign=+1;
		inputHugeInteger(intt);
	}
	
	private void reverse() 
   {
		int tmp;
		
		for (int i=0;i<length/2;i++) 
      {
			tmp=nr[i];
			nr[i]=nr[length-i-1];
			nr[length-i-1]=tmp;
		}      
	}

	public boolean equalsTo(HugeInteger c) 
   {
		
		for (int i=0;i<40;i++) 
      {
			if (nr[i]!=c.nr[i]) return false;
		}
		if (sign==c.sign )return true;
		return false;
	}
	
	public boolean isZero() 
   {
		for (int i=0;i<40;i++)
			if (nr[i]!=0) return false;
		return true;
	}
	
	public boolean isGreaterOrEqualTo(HugeInteger c) 
   {
		if ((subtractHugeIntegers(c).sign==1)|(subtractHugeIntegers(c).isZero())) return true;
		return false;
	}

	public boolean isLessOrEqualTo(HugeInteger c) 
   {
		if ((subtractHugeIntegers(c).sign==-1)|(subtractHugeIntegers(c).isZero())) return true;
		return false;
	}
	
	public boolean isGreaterThan(HugeInteger c) 
   {
		return !(isLessOrEqualTo(c));
	}

	public boolean isLessThan(HugeInteger c) 
   {
		return !(isGreaterOrEqualTo(c));
	}

// private HugeInteger interval(HugeInteger div) 
//   {
//     HugeInteger valmin,valmax, valmean, tmp;
//     int stemp;
//      
//      if (div.equalsTo(new HugeInteger().addOne())) return this;
//      if (this.isLessThan(div)) return new HugeInteger();
//      valmax=this;valmin=new HugeInteger();
//      do {
//         valmean=valmax.subtractHugeIntegers(valmin).divideByTwo().addHugeIntegers(valmin);
//         tmp=valmean.multiplyHugeIntegers(div);
//         if (tmp.equalsTo(this)) return valmean;
//         if (tmp.isLessOrEqualTo(this)&&(valmean.addOne().multiplyHugeIntegers(div).isGreaterOrEqualTo(this))) return valmean;
//         if (tmp.isLessThan(this)) 
//            valmin=valmean;
//         else 
//            valmax=valmean;
//     } while (true);  
      
   //}  
   
}
