package  zh.tools.io;

//  (c) Dan Meany - BSD license

import  java.util.StringTokenizer;
import  java.util.Vector;

public   class  SqlFormat  {
 
public   static   void  main(String[] args)  {

  System.out.println(format(
" \t\t " ,
    
" SELECT * FROM TB WHERE A=A AND B=B ORDER BY C " ));
 }


 
public   static  String format(String table, String sql)  {
  
if (sql == null return   " null " ;
  String text 
=   new  SQLFormatter().setText(sql).format().getText();
  String result 
=   "" ;
  
//  String s="sdf\nsdf\n";
  StringTokenizer st  =   new  StringTokenizer(text,  " \n " );
  
while  (st.hasMoreTokens())  {
   String row 
=  st.nextToken();
   row 
=  table  +  row;
   result 
+=  row;
  }


  
// return result;
   return   "" ;
 }

}


class  SQLFormatter  {

 
private   static   boolean  isName(String s)  {
  
return   ! isIn(
    s,
    
" |SELECT|FROM|WHERE|ORDER BY|GROUP BY|HAVING|UPDATE|SET|INSERT|INTO|VALUES|DELETE|UNION|ALL|MINUS| " )
    
&&   ! isIn(s,
      
" |COUNT|SUM|AVG|MIN|MAX|DISTINCT|AS|ANY|AND|OR|XOR|NOT|LIKE|IN|EXISTS|IS|NULL| " );
 }


 
private   static   boolean  isFunction(String s)  {
  
return  isIn(s,  " |COUNT|SUM|AVG|MIN|MAX| " );
 }


 
public  SQLFormatter format()  {
  String s 
=  sText;
  Vector vector 
=   new  Vector();
  
for  ( int  i  =   0 ; i  <  s.length(); i ++ {
   
for  ( int  j  =   0 ; j  <  sEscapes.length; j ++ {
    String s1 
=  sEscapes[j][ 0 ];
    String s3 
=  sEscapes[j][ 1 ];
    String s5 
=  sEscapes[j][ 2 ];
    
if  ( ! s.regionMatches(i, s1,  0 , s1.length()))
     
continue ;
    
int  j1  =  i  +  s1.length();
    
int  k1  =  s.indexOf(s3, j1);
    
if  (k1  ==   - 1 {
     k1 
=  s.indexOf( " \n " , j1);
     
if  (k1  ==   - 1 {
      k1 
=  s.indexOf( " \r " , j1);
      
if  (k1  ==   - 1 )
       k1 
=  s.length()  -   1 ;
     }

     k1
++ ;
    }
  else   {
     k1 
+=  s3.length();
    }

    String s6 
=  s.substring(i, k1);
    
if  (s5.equals( " 2 " ))
     s6 
=   " /* "   +  s6.trim().substring( 2 +   "  */ " ;
    vector.addElement(s6);
    String s7 
=  s.substring( 0 , i);
    String s8;
    
if  (k1  <  s.length())
     s8 
=  s.substring(k1);
    
else
     s8 
=   "" ;
    String s9 
=   " \001 " ;
    
if  ( ! s5.equals( "" ))  {
     
if  ( ! s7.endsWith( "   " ))
      s9 
=   "   "   +  s9;
     
if  ( ! s8.startsWith( "   " ))
      s9 
=  s9  +   "   " ;
    }

    s 
=  s7  +  s9  +  s8;
    
break ;
   }


  }


  Vector vector1 
=   new  Vector();
  
for  (StringTokenizer stringtokenizer  =   new  StringTokenizer(s); stringtokenizer
    .hasMoreTokens();) 
{
   String s2 
=  stringtokenizer.nextToken();
   
for  (StringTokenizer stringtokenizer1  =   new  StringTokenizer(s2,
     
" (), " true ); stringtokenizer1.hasMoreTokens(); vector1
     .addElement(stringtokenizer1.nextToken()))
    ;
  }


  
for  ( int  k  =   0 ; k  <  vector1.size()  -   1 ; k ++ {
   String s4 
=  (String) vector1.elementAt(k)  +   "   "
     
+  (String) vector1.elementAt(k  +   1 );
   
if  (isMajor(s4))  {
    vector1.setElementAt(s4, k);
    vector1.removeElementAt(k 
+   1 );
   }

  }


  
int  l  =  vector1.size();
  String as[] 
=   new  String[l  +=   2 ];
  as[
0 =   "" ;
  as[l 
-   1 =   "" ;
  
for  ( int  i1  =   0 ; i1  <  vector1.size(); i1 ++ )
   as[i1 
+   1 =  (String) vector1.elementAt(i1);

  
int  ai[]  =   new   int [l];
  
int  ai1[]  =   new   int [l];
  
for  ( int  l1  =   0 ; l1  <  l; l1 ++ {
   
boolean  flag  =   false ;
   
if  (isMajor(as[l1]))
    flag 
=  bCapitalizeMajor;
   
if  (isMinor(as[l1]))
    flag 
=  bCapitalizeMinor;
   
if  (isName(as[l1]))
    flag 
=  bCapitalizeNames;
   
if  (flag)
    as[l1] 
=  as[l1].toUpperCase();
  }


  
for  ( int  i2  =   1 ; i2  <  l  -   1 ; i2 ++ {
   ai[i2] 
=   1 ;
   
if  (isMajor(as[i2]))  {
    ai[i2 
-   1 =   2 ;
    ai[i2] 
=   2 ;
   }
  else   if  (as[i2].equals( " , " ))  {
    ai[i2] 
=   2 ;
    ai[i2 
-   1 =   0 ;
   }
  else   if  (as[i2].equals( " ( " ))  {
    ai[i2] 
=   0 ;
    
if  (isFunction(as[i2  -   1 ])  ||  isName(as[i2  -   1 ]))
     ai[i2 
-   1 =   0 ;
   }
  else   if  (as[i2].equals( " ) " ))
    ai[i2 
-   1 =   0 ;
   
else   if  (as[i2].equalsIgnoreCase( " AND " ))
    
if  (bNewLineBeforeAnd)
     ai[i2 
-   1 =   2 ;
    
else
     ai[i2] 
=   2 ;
  }


  ai[l 
-   2 =   2 ;
  
int  j2  =   0 ;
  
int  ai2[]  =   new   int [ 16 ];
  
for  ( int  k2  =   0 ; k2  <  l; k2 ++ {
   
if  (as[k2].equals( " ) " ))
    
if  (ai2[j2]  ==   0 {
     j2
-- ;
     
if  (k2  >   0 )
      ai[k2 
-   1 =   2 ;
    }
  else   {
     ai2[j2]
-- ;
    }

   
if  (isMajor(as[k2]))
    ai1[k2] 
=  j2  *   2 ;
   
else
    ai1[k2] 
=  j2  *   2   +   1 ;
   
if  (as[k2].equals( " ( " ))
    
if  (isSubSelect(as[k2  +   1 ]))  {
     
if  (j2  <   16 )
      j2
++ ;
     ai2[j2] 
=   0 ;
    }
  else   {
     ai2[j2]
++ ;
    }

  }


  String as1[] 
=   new  String[ 3 ];
  as1[
0 =   "" ;
  as1[
1 =   "   " ;
  as1[
2 =  sNewLine;
  StringBuffer stringbuffer 
=   new  StringBuffer();
  
for  ( int  l2  =   1 ; l2  <  l  -   1 ; l2 ++ {
   
if  (ai[l2  -   1 ==   2 )
    stringbuffer.append(repeatString(sIndent, ai1[l2]));
   stringbuffer.append(as[l2] 
+  as1[ai[l2]]);
  }


  s 
=  stringbuffer.toString();
  
for  ( int  i3  =   0 ; i3  <  vector.size(); i3 ++ {
   
int  j3  =  s.indexOf( " \001 " );
   s 
=  s.substring( 0 , j3)  +  (String) vector.elementAt(i3)
     
+  s.substring(j3  +   1 );
  }


  sText 
=  s;
  
if  (bDebug)  {
   StringBuffer stringbuffer1 
=   new  StringBuffer();
   stringbuffer1.append(
" Tokens:\r\n " );
   
for  ( int  k3  =   1 ; k3  <  l  -   1 ; k3 ++ )
    stringbuffer1.append(
""   +  ai1[k3]  +   "  [ "   +  as[k3]  +   " "
      
+  ai[k3]  +   " \r\n " );

   stringbuffer1.append(
" Escapes:\r\n " );
   
for  ( int  l3  =   0 ; l3  <  vector.size(); l3 ++ )
    stringbuffer1.append((String) vector.elementAt(l3) 
+   " \r\n " );

   sDebugString 
=  stringbuffer1.toString();
  }

  
return   this ;
 }


 
public   void  setNewLineBeforeAnd( boolean  flag)  {
  bNewLineBeforeAnd 
=  flag;
 }


 
public  String getDebugString()  {
  
return  sDebugString;
 }


 
public   void  setNewLine(String s)  {
  
for  ( int  i  =   0 ; i  <  sEscapes.length; i ++ {
   
for  ( int  j  =   0 ; j  <  sEscapes[ 0 ].length; j ++ )
    
if  (sEscapes[i][j].equals(sNewLine))
     sEscapes[i][j] 
=  s;

  }


  sNewLine 
=  s;
 }


 SQLFormatter() 
{
  sText 
=   "" ;
  sNewLine 
=   " \r\n " ;
  sIndent 
=   "     " ;
  sDebugString 
=   "" ;
  bCapitalizeMajor 
=   false ;
  bCapitalizeMinor 
=   false ;
  bCapitalizeNames 
=   false ;
  bNewLineBeforeAnd 
=   true ;
  bDebug 
=   false ;
 }


 
private   static   boolean  isMinor(String s)  {
  
return  isIn(s,
    
" |COUNT|SUM|AVG|MIN|MAX|DISTINCT|AS|ANY|AND|OR|XOR|NOT|LIKE|IN|EXISTS|IS|NULL| " );
 }


 
private   static   boolean  isIn(String s, String s1)  {
  
return  s1.indexOf( " | "   +  s.toUpperCase()  +   " | " >   - 1 ;
 }


 
private   static   boolean  isSubSelect(String s)  {
  
return  isIn(s,  " |SELECT| " );
 }


 
public   void  setCapitalizeMajor( boolean  flag)  {
  bCapitalizeMajor 
=  flag;
 }


 
public   void  setCapitalizeNames( boolean  flag)  {
  bCapitalizeNames 
=  flag;
 }


 
public   void  setIndent( int  i)  {
  
if  (i  <   0 )
   sIndent 
=   " \t " ;
  
else
   sIndent 
=  repeatString( "   " , i);
 }


 
public   void  setDebug( boolean  flag)  {
  bDebug 
=  flag;
 }


 
private  String repeatString(String s,  int  i)  {
  
if  (i  <   1 )
   
return   "" ;
  StringBuffer stringbuffer 
=   new  StringBuffer(s.length()  *  i);
  
for  ( int  j  =   0 ; j  <  i; j ++ )
   stringbuffer.append(s);

  
return  stringbuffer.toString();
 }


 
public   void  setCapitalizeMinor( boolean  flag)  {
  bCapitalizeMinor 
=  flag;
 }


 
private   static   boolean  isMajor(String s)  {
  
return  isIn(
    s,
    
" |SELECT|FROM|WHERE|ORDER BY|GROUP BY|HAVING|UPDATE|SET|INSERT|INTO|VALUES|DELETE|UNION|ALL|MINUS| " );
 }


 
public  String getText()  {
  
return  sText;
 }


 
public  SQLFormatter setText(String s)  {
  sText 
=  s;
  
return   this ;
 }


 
private   static   final  String MAJOR_WORDS  =   " |SELECT|FROM|WHERE|ORDER BY|GROUP BY|HAVING|UPDATE|SET|INSERT|INTO|VALUES|DELETE|UNION|ALL|MINUS| " ;

 
private   static   final  String MINOR_WORDS  =   " |COUNT|SUM|AVG|MIN|MAX|DISTINCT|AS|ANY|AND|OR|XOR|NOT|LIKE|IN|EXISTS|IS|NULL| " ;

 
private   static   final  String FUNCTION_WORDS  =   " |COUNT|SUM|AVG|MIN|MAX| " ;

 
private   static   final  String SUB_SELECT  =   " |SELECT| " ;

 
private   static   final  String ESCAPE_TOKEN  =   " \001 " ;

 
private   static   final  String DELIMITERS  =   " (), " ;

 
private   static   final   int  MAX_INDENTS  =   16 ;

 
private   static   final   int  NOTHING  =   0 ;

 
private   static   final   int  SPACE  =   1 ;

 
private   static   final   int  NEW_LINE  =   2 ;

 
private  String sEscapes[][]  =   " ' " " ' " ""  } " \ "" " \ "" ""  } ,
   
" /* " " */ " " 1 "  } " -- " " \r\n " " 2 "  }  }
;

 
private  String sText;

 
private  String sNewLine;

 
private  String sIndent;

 
private  String sDebugString;

 
private   boolean  bCapitalizeMajor;

 
private   boolean  bCapitalizeMinor;

 
private   boolean  bCapitalizeNames;

 
private   boolean  bNewLineBeforeAnd;

 
private   boolean  bDebug;
}