package com.eactive.eai.transformer.util; 

import com.eactive.eai.transformer.function.util.CodeConversion;

public class EbcdicDumpUtil 
{
    public static final char   SPACE = ' ';

    public static final char   ZERO  = '0';
    
    public static final String[] EMPTY_STRING_ARRAY = new String[0];
    
    private EbcdicDumpUtil() {
    	
    }
//    public static void printEbcdicDump(byte[] ebcdicBytes) throws Exception {
//		String[] msg = makeEbcdicDumpFormat(ebcdicBytes);
//		for(int i=0; i<msg.length; i++) {
//			System.out.println(msg[i]);
//		}
//	}
	
    /**
     * BYTE ARRAY값을 HEXA STRING으로 변환하여 String을 리턴한다.
     * @param abyte
     * @return
     */
    public static String byte2Hex(byte[] abyte) {
        StringBuilder s = new StringBuilder();
        if (abyte == null)
            return s.toString();
        for (int i = 0; i < abyte.length; i++)
            s.append( Integer.toHexString((abyte[i] & 0xf0) >> 4).toUpperCase() ).append( Integer.toHexString(abyte[i] & 0xf).toUpperCase() );
        return s.toString();
    }

    /**
     * 주어진 String값을 주어진 길이많큼 Padding/Trim한다.
     * @param svalue - 입력스트링
     * @param isRightJustify - true이면 RIGHT JUSTIFY, false이면 LEFT JUSTIFY 
     * @param padding - Padding 문자
     * @param length - 리턴할 스트링의 바이트수
     * @return 포맷팅된 String결과 
     */
    public static String stringFormat(String svalue, boolean isRightJustify, char padding, int length) {
        if ( svalue == null ) return svalue;
        
        StringBuilder mpad 	= new StringBuilder();
        StringBuilder fmtStr = new StringBuilder();
        
        String tvalue 	= svalue;
        int pLength 	= 0;

        pLength = length - svalue.getBytes().length;  
        
        if (pLength == 0) 
            return svalue;
        else if ( pLength < 0) {
            byte[] abytes = null;
            if (isRightJustify) {
            	abytes = (new String( svalue.getBytes(), -(pLength), length)).getBytes(); 
            } else {
            	abytes = (new String( svalue.getBytes(), 0, length)).getBytes();
            }
            
            if ( abytes.length == length ) {
                return  new String( abytes );
            } else {
              tvalue = new String( abytes );
              pLength = length - tvalue.length();
            }
        }
        
        for(int i =0; i < pLength ; i++) {
            mpad.append( padding );
        }
        
        if ( isRightJustify ) {
            return fmtStr.append(mpad).append(tvalue).toString();
        } else {
            return fmtStr.append(tvalue).append(mpad).toString();
        }
    }
    
    
    /**
     * 송수신EBCDIC 전문에 대한 DUMP를 프린트할 수 있는 포맷으로 변환하여 String Array로 리턴한다.
     * @param bytes
     * @return
     */
    public static String[] makeEbcdicDumpFormat(byte[] ebcdicBytes) {
    	
    	byte[] bytes = CodeConversion.meToAsc(ebcdicBytes);
    	
        if (bytes == null || bytes.length == 0)
            return EMPTY_STRING_ARRAY;

        String[] dumps = new String[bytes.length / 16 + ((bytes.length % 16) == 0 ? 4 : 5)+1];
        dumps[0]	= "/==========.========================================..==================.";
        dumps[1]	= "|  Offset  | 0 1 2 3   4 5 6 7   8 9 A B   C D E F  || U S E R  D A T A |";
        dumps[2]	= "|----------+----------------------------------------||------------------|";
        dumps[dumps.length - 2]	= "'=========='========================================''==================/";
        dumps[dumps.length - 1]	= "- Total DATA Size ["+ebcdicBytes.length+"]";
        
        int		 len   = 0;
        byte	 PERIOD = 0x2E;
        char     aChar  = ' ';
        boolean  isDBCS = false;
        boolean  isHalfDBCS = false;
        
        for (int i = 3; i < dumps.length - 2; i++) {
            len = ( ((bytes.length - (i - 2) * 16) >= 0) ? 16 : (bytes.length - (i - 3)*16) );
            byte[]   ebcdicBuf   = new byte[len];
            byte[]   asciiBuf   = new byte[len];
            
            StringBuilder strBuf = new StringBuilder();
            
            // 2020.02.10 : SOSI가 깨진경우 계산이 안맞는다.
            if(((i-3)*16) + len > ebcdicBytes.length) {
            	dumps[i] = strBuf.append("(SOSI BREAK)  invalid position = " + ((i-3)*16 + len)).toString();
            	break;
            }
            
            System.arraycopy( ebcdicBytes, (i-3)*16, ebcdicBuf, 0, len );
            System.arraycopy( bytes,       (i-3)*16, asciiBuf,  0, len );
            
            //dumps[i] = EMPTY_STRING;
            
            strBuf.append("| ").append( stringFormat( ""+((i-3)*16), true, ZERO, 8) ).append(" | ");
            
            String	 	 hexStr = byte2Hex( ebcdicBuf );
            StringBuilder fmtStr = new StringBuilder();
            
            int		 k = hexStr.length()/8 + ((hexStr.length() % 8) == 0 ? 0 : 1);
            for (int j=0; j < k ; j++) {
                int l = ((hexStr.length() - (j+1)*8 ) >= 0 ? 8 : (hexStr.length() - j*8 ));
                fmtStr.append( hexStr.substring(j*8, j*8 + l ) ).append("  ");
            }
            
            strBuf.append( stringFormat(fmtStr.toString(), false, SPACE, 39) ).append("|| ");

            k = 0;
            // 한글 및 특수문자가 깨지게 표시되는 것 을 방지한다.
            for ( int j=0; j < len; j++) {
                if ( asciiBuf[j] >> 7 == 0 ) {
                    // Single Byte Character
                    if ( isDBCS ) {
                        isDBCS = false;
                        if ( k != 0 &&  ((k % 2) == 1 )) {
                            asciiBuf[j - 1] = PERIOD;
                        }
                    }
                    aChar = (char)asciiBuf[j];
                    if ( Character.isWhitespace( aChar ) || Character.isISOControl( aChar ) || asciiBuf[j] == 0 ) {
                        asciiBuf[j] = PERIOD;
                    }
                    continue;
                }
                // Double Bytes Character.
                if ( !isDBCS ) isDBCS = true;
                if ( j == 0 && isHalfDBCS ) {
                    asciiBuf[j] = PERIOD;
                    isDBCS = false;
                    continue;
                }
                // To check the DBCS pairwise
                k++;
            }
            if ( isDBCS && ((k%2)==1) ) {
                asciiBuf[ len -1 ] = PERIOD;
                isHalfDBCS = true;
            } else {
                isHalfDBCS = false;
            }
            
            dumps[i] =  strBuf.append( stringFormat(new String(asciiBuf), false, SPACE, 16) ).append(" |").toString();
        }
        return dumps;
    } 
} 
