/*
 * Copyright 1998-2003 Andreas Schmidt and friends
 * for use with Delphi 1 - 7
 * http://members.tripod.de/AJSchmidt/index.html
 * http://mitglied.lycos.de/AJSchmidt/fbarcode.zip
 *
 * moved to Java by Heiko Wenzel
 *
 * Created on 7. April 2004, 10:44
 */

package it.businesslogic.ireport.barcode;

import java.util.*;
import java.awt.*;
import java.math.*;
import java.lang.*;

public class Bc extends javax.swing.JPanel {
    public class TBarcodeType {
        public final static int bcCode_2_5_interleaved = 0;
        public final static int bcCode_2_5_industrial = 1;
        public final static int bcCode_2_5_matrix = 2;
        public final static int bcCode39 = 3;
        public final static int bcCode39Extended = 4;
        public final static int bcCode128A = 5;
        public final static int bcCode128B = 6;
        public final static int bcCode128C = 7;
        public final static int bcCode93 = 8;
        public final static int bcCode93Extended = 9;
        public final static int bcCodeMSI = 10;
        public final static int bcCodePostNet = 11;
        public final static int bcCodeCodabar = 12;
        public final static int bcCodeEAN8 = 13;
        public final static int bcCodeEAN13 = 14;
        public final static int bcCodeUPC_A = 15;
        public final static int bcCodeUPC_E0 = 16;
        public final static int bcCodeUPC_E1 = 17;
        public final static int bcCodeUPC_Supp2 = 18;
        public final static int bcCodeUPC_Supp5 = 19;
        public final static int bcCodeEAN128A = 20;
        public final static int bcCodeEAN128B = 21;
        public final static int bcCodeEAN128C = 22;
    }
    
    public class TBarLineType {
        public final static int white = 0;
        public final static int black = 1;
        public final static int black_half = 2;
    }
    
    public class TBarcodeOption {
        public final static int bcoNone = 0;
        public final static int bcoCode = 1;
        public final static int bcoTyp = 2;
        public final static int bcoBoth = 3;
    }
    
    public class TShowTextPosition {
        public final static int stpTopLeft = 0;
        public final static int stpTopRight = 1;
        public final static int stpTopCenter = 2;
        public final static int stpBottomLeft = 3;
        public final static int stpBottomRight = 4;
        public final static int stpBottomCenter = 5;
    }
    
    public class TCheckSumMethod {
        public final static int csmNone = 0;
        public final static int csmModulo10 = 1;
    }
    
    
    private class TBcData {
        private String name; // Name of Barcode
        private boolean num; // numeric data only
        
        public TBcData(String name, boolean num) {
            this.name = name;
            this.num = num;
        }
        public String getName() {
            return name;
        }
        public boolean getNum() {
            return num;
        }
    }
    
    private final TBcData[] BcData = {
        new TBcData("2_5_interleaved", true),
        new TBcData("2_5_industrial", true),
        new TBcData("2_5_matrix", true),
        new TBcData("Code39", false),
        new TBcData("Code39 Extended", false),
        new TBcData("Code128A", false),
        new TBcData("Code128B", false),
        new TBcData("Code128C", true),
        new TBcData("Code93", false),
        new TBcData("Code93 Extended", false),
        new TBcData("MSI", true),
        new TBcData("PostNet", true),
        new TBcData("Codebar", false),
        new TBcData("EAN8", true),
        new TBcData("EAN13", true),
        new TBcData("UPC_A", true),
        new TBcData("UPC_E0", true),
        new TBcData("UPC_E1", true),
        new TBcData("UPC Supp2", true),
        new TBcData("UPC Supp5", true),
        new TBcData("EAN128A", false),
        new TBcData("EAN128B", false),
        new TBcData("EAN128C", true)
    };
    
    /**
     *      {Pattern for Barcode EAN Charset A}
     *      {L1   S1   L2   S2}
     */
    private final String[] tabelle_EAN_A = {
        "2605", // 0
        "1615", // 1
        "1516", // 2
        "0805", // 3
        "0526", // 4
        "0625", // 5
        "0508", // 6
        "0706", // 7
        "0607", // 8
        "2506"  // 9
    };
    
    /**
     *   {Pattern for Barcode EAN Charset C}
     *        {S1   L1   S2   L2}
     */
    private final String[] tabelle_EAN_C = {
        "7150",  // 0
        "6160",  // 1
        "6061",  // 2
        "5350",  // 3
        "5071",  // 4
        "5170",  // 5
        "5053",  // 6
        "5251",  // 7
        "5152",  // 8
        "7051"   // 9
    };
    
    /** Creates new form BeanForm */
    public Bc() {
        FType = TBarcodeType.bcCodeEAN8;
        FHeight = 50;
        FModul = 2;
        FRatio = 2;
        FText = "12345678";
        
        initComponents();
    }
    
    public class bcUtil {
        /**
         * function Convert(const s: string): string;
         * var
         * i, v: integer;
         * begin
         * Result := s; { same Length as Input - string }
         * for i := 1 to Length(s) do begin
         * v := ord(s[i]) - 1;
         *
         * if odd(i) then
         * Inc(v, 5);
         * Result[i] := Chr(v);
         * end;
         * end;
         */
        public String convert(final String s){
            int v;
            byte[] b = s.getBytes();
            for (int i = 0; i < s.length(); i++) {
                v = b[i] - 1;
                if ((i % 2) == 0)
                    v = v + 5;
                b[i] = new Integer(v).byteValue();
            }
            return new String(b);
        }
        
        
        /**
         * function quersumme(x: integer): integer;
         * var
         * sum: integer;
         * begin
         * sum := 0;
         *
         * while x > 0 do begin
         * sum := sum + (x mod 10);
         * x := x div 10;
         * end;
         * result := sum;
         * end;
         */
        public int quersumme(int x) {
            int sum = 0;
            while (x > 0) {
                sum = sum + (x % 10);
                x = x / 10;
            }
            return sum;
        }
        
        
        /**
         * function Rotate2D(p: TPoint; alpha: double): TPoint;
         * var
         * sinus, cosinus: Extended;
         * begin
         *
         * // sinus   := sin(alpha);
         * // cosinus := cos(alpha);
         *
         * // twice as fast than calc sin() and cos()
         * SinCos(alpha, sinus, cosinus);
         *
         * result.x := Round(p.x * cosinus + p.y * sinus);
         * result.y := Round(-p.x * sinus + p.y * cosinus);
         * end;
         */
        public Point rotate2D(Point p, double alpha) {
            double sinus = Math.sin(alpha);
            double cosinus = Math.cos(alpha);
            int x = new Long(Math.round(p.x * cosinus + p.y * sinus)).intValue();
            int y = new Long(Math.round(p.y * cosinus - p.x * sinus)).intValue();
            return new Point(x , y);
        }
        
        /**
         * function Translate2D(a, b: TPoint): TPoint;
         * begin
         * result.x := a.x + b.x;
         * result.y := a.y + b.y;
         * end;
         */
        public Point translate2D(Point a, Point b) {
            return new Point(a.x + b.x, a.y + b.y);
        }
        
        
        /**
         * Move the orgin so that when point is rotated by alpha, the rect
         * between point and orgin stays in the visible quadrant.
         *
         * function TranslateQuad2D(const alpha: double; const orgin, point: TPoint): TPoint;
         * var
         * alphacos: Extended;
         * alphasin: Extended;
         * moveby: TPoint;
         * begin
         *      SinCos(alpha, alphasin, alphacos);
         *
         * if alphasin >= 0 then begin
         * if alphacos >= 0 then begin
         *
         * { 1. Quadrant }
         * moveby.x := 0;
         * moveby.y := Round(alphasin * point.x);
         * end
         * else begin
         * { 2. Quadrant }
         * moveby.x := -Round(alphacos * point.x);
         * moveby.y := Round(alphasin * point.x - alphacos * point.y);
         * end;
         * end
         * else begin
         * if alphacos >= 0 then begin
         * { 4. quadrant }
         * moveby.x := -Round(alphasin * point.y);
         * moveby.y := 0;
         * end
         * else begin
         * { 3. quadrant }
         * moveby.x := -Round(alphacos * point.x) - Round(alphasin * point.y);
         * moveby.y := -Round(alphacos * point.y);
         * end;
         * end;
         * Result := Translate2D(orgin, moveby);
         * end;
         */
        public Point translateQuad2D(final double alpha, final Point orgin, final Point point) {
            Point moveby = new Point();
            double alphasin = Math.sin(alpha);
            double alphacos = Math.cos(alpha);
            
            if (alphasin >= 0) {
                if (alphacos >= 0) {
                    // 1. Quadrant
                    moveby.x = 0;
                    moveby.y = new Double(alphasin * point.x).intValue();
                } else {
                    // 2. Quadrant
                    moveby.x = - new Double(alphacos * point.x).intValue();
                    moveby.y = new Double(alphasin * point.x -  alphacos * point.y).intValue();
                }
            } else {
                if (alphacos >= 0) {
                    // 4. quadrant
                    moveby.x = - new Double(alphasin * point.y).intValue();
                    moveby.y = 0;
                } else {
                    // 3. quadrant
                    moveby.x = -new Double(alphacos * point.x - alphasin * point.y).intValue();
                    moveby.y = -new Double(alphacos * point.y).intValue();
                }
            }
            return translate2D(orgin, moveby);
        }
    }
    
    private int FHeight;
    private String FText;
    private int FTop;
    private int FLeft;
    private int FModul = 1;
    private double FRatio = 2;
    private int FType = TBarcodeType.bcCodeEAN13;
    private boolean FCheckSum = false;
    private int FShowText = TBarcodeOption.bcoNone;
    private double FAngle = 0;
    private Color FColor = Color.white;
    private Color FColorBar = Color.black;
    private int FCheckSumMethod = TCheckSumMethod.csmModulo10;
    
    private int[] modules = new int[4];
    private Font FShowTextFont = new Font("SansSerif", Font.PLAIN, 10);
    private TShowTextPosition FShowTextPosition;
    
    /**
     * Utility field used by bound properties.
     */
    private java.beans.PropertyChangeSupport propertyChangeSupport =  new java.beans.PropertyChangeSupport(this);
    
    /**
     * calculate the width and the linetype of a sigle bar
     *
     *  Code   Line-Color      Width               Height
     * ------------------------------------------------------------------
     *  '0'   white           100%                full
     *  '1'   white           100%*Ratio          full
     *  '2'   white           150%*Ratio          full
     *  '3'   white           200%*Ratio          full
     *  '5'   black           100%                full
     *  '6'   black           100%*Ratio          full
     *  '7'   black           150%*Ratio          full
     *  '8'   black           200%*Ratio          full
     *  'A'   black           100%                2/5  (used for PostNet)
     *  'B'   black           100%*Ratio          2/5  (used for PostNet)
     *  'C'   black           150%*Ratio          2/5  (used for PostNet)
     *  'D'   black           200%*Ratio          2/5  (used for PostNet)
     *
     * procedure TAsBarcode.OneBarProps(code: char; var Width: integer; var lt: TBarLineType);
     * begin
     *   case code of
     *     '0': begin
     *         width := modules[0];
     *         lt := white;
     *       end;
     *     '1': begin
     *         width := modules[1];
     *         lt := white;
     *       end;
     *     '2': begin
     *         width := modules[2];
     *         lt := white;
     *       end;
     *     '3': begin
     *         width := modules[3];
     *         lt := white;
     *       end;
     *
     *     '5': begin
     *         width := modules[0];
     *         lt := black;
     *       end;
     *     '6': begin
     *         width := modules[1];
     *         lt := black;
     *       end;
     *     '7': begin
     *         width := modules[2];
     *         lt := black;
     *       end;
     *     '8': begin
     *         width := modules[3];
     *         lt := black;
     *       end;
     *
     *     'A': begin
     *         width := modules[0];
     *         lt := black_half;
     *       end;
     *     'B': begin
     *         width := modules[1];
     *         lt := black_half;
     *       end;
     *     'C': begin
     *         width := modules[2];
     *         lt := black_half;
     *       end;
     *     'D': begin
     *         width := modules[3];
     *         lt := black_half;
     *       end;
     *   else begin
     *       {something went wrong  :-(  }
     *       {mistyped pattern table}
     *       raise Exception.CreateFmt('%s: internal Error', [self.ClassName]);
     *     end;
     *   end;
     * end;
     */
    private void oneBarProps(char code, int[] width, int[] lt) {
        try {
            switch(code) {
                case '0': width[0] = modules[0];
                lt[0] = TBarLineType.white;
                break;
                
                case '1': width[0] = modules[1];
                lt[0] = TBarLineType.white;
                break;
                
                case '2': width[0] = modules[2];
                lt[0] = TBarLineType.white;
                break;
                
                case '3': width[0] = modules[3];
                lt[0] = TBarLineType.white;
                break;
                
                case '5': width[0] = modules[0];
                lt[0] = TBarLineType.black;
                break;
                
                case '6': width[0] = modules[1];
                lt[0] = TBarLineType.black;
                break;
                
                case '7': width[0] = modules[2];
                lt[0] = TBarLineType.black;
                break;
                
                case '8': width[0] = modules[3];
                lt[0] = TBarLineType.black;
                break;
                
                case 'A': width[0] = modules[0];
                lt[0] = TBarLineType.black_half;
                break;
                
                case 'B': width[0] = modules[1];
                lt[0] = TBarLineType.black_half;
                break;
                
                case 'C': width[0] = modules[2];
                lt[0] = TBarLineType.black_half;
                break;
                
                case 'D': width[0] = modules[3];
                lt[0] = TBarLineType.black_half;
                break;
                
                default:
                    throw new Exception("Internal error method Bc.oneBarProps" );
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * Draw the Barcode
     *
     * Parameter :
     * 'data' holds the pattern for a Barcode.
     * A barcode begins always with a black line and
     * ends with a black line.
     *
     * The white Lines builds the space between the black Lines.
     *
     * A black line must always followed by a white Line and vica versa.
     *
     * Examples:
     *   '50505'   // 3 thin black Lines with 2 thin white Lines
     *   '606'     // 2 fat black Lines with 1 thin white Line
     *
     *   '5605015' // Error
     *
     * data[] : see procedure OneBarProps
     *
     *
     *
     * procedure TAsBarcode.DoLines(data: string; Canvas: TCanvas);
     *
     * var
     *   i: integer;
     *   lt: TBarLineType;
     *   xadd: integer;
     *   width, height: integer;
     *   a, b, c, d, {Edges of a line (we need 4 Point because the line}
     *   {is a recangle}
     *   orgin: TPoint;
     *   alpha: double;
     * begin
     *   xadd := 0;
     *   orgin.x := FLeft;
     *   orgin.y := FTop;
     *
     *   alpha := FAngle / 180.0 * pi;
     *
     *   { Move the orgin so the entire barcode ends up in the visible region. }
     *   orgin := TranslateQuad2D(alpha, orgin, Point(Self.Width, Self.Height));
     *
     *   with Canvas do begin
     *     Pen.Width := 1;
     *
     *     for i := 1 to Length(data) do {examine the pattern string} begin
     *
     *       {
     *       input:  pattern code
     *       output: Width and Linetype
     *       }
     *       OneBarProps(data[i], width, lt);
     *
     *       if (lt = black) or (lt = black_half) then begin
     *         Pen.Color := FColorBar;
     *       end
     *       else begin
     *         Pen.Color := FColor;
     *       end;
     *       Brush.Color := Pen.Color;
     *
     *       if lt = black_half then
     *         height := FHeight * 2 div 5
     *       else
     *         height := FHeight;
     *
     *       a.x := xadd;
     *       a.y := 0;
     *
     *       b.x := xadd;
     *       b.y := height;
     *
     *       {c.x := xadd+width;}
     *       c.x := xadd + Width - 1; {23.04.1999 Line was 1 Pixel too wide}
     *       c.y := Height;
     *
     *       {d.x := xadd+width;}
     *       d.x := xadd + Width - 1; {23.04.1999 Line was 1 Pixel too wide}
     *       d.y := 0;
     *
     *       {a,b,c,d builds the rectangle we want to draw}
     *
     *       {rotate the rectangle}
     *       a := Translate2D(Rotate2D(a, alpha), orgin);
     *       b := Translate2D(Rotate2D(b, alpha), orgin);
     *       c := Translate2D(Rotate2D(c, alpha), orgin);
     *       d := Translate2D(Rotate2D(d, alpha), orgin);
     *
     *       {draw the rectangle}
     *       Polygon([a, b, c, d]);
     *
     *       xadd := xadd + width;
     *     end;
     *   end;
     * end;
     *
     */
    
    private Dimension getBarExtents() {
        bcUtil bcU = new Bc.bcUtil();
        double alpha = FAngle / 180 * Math.PI;
        Point orgin = bcU.translateQuad2D(alpha, new Point(FLeft, FTop), new Point(getWidth(), FHeight));
        
        Point a = new Point(0, 0);
        Point b = new Point(0, FHeight);
        Point c = new Point(getWidth() - 1, FHeight);
        Point d = new Point(getWidth() - 1, 0);
        
        // rotate the rectangle}
        a = bcU.translate2D(bcU.rotate2D(a, alpha), orgin);
        b = bcU.translate2D(bcU.rotate2D(b, alpha), orgin);
        c = bcU.translate2D(bcU.rotate2D(c, alpha), orgin);
        d = bcU.translate2D(bcU.rotate2D(d, alpha), orgin);
        
        int exX = 0;
        int exY = 0;
        if (a.x > exX) exX = a.x;
        if (b.x > exX) exX = b.x;
        if (c.x > exX) exX = c.x;
        if (d.x > exX) exX = d.x;
        
        if (a.y > exY) exY = a.y;
        if (b.y > exY) exY = b.y;
        if (c.y > exY) exY = c.y;
        if (d.y > exY) exY = d.y;
        return new Dimension(exX, exY);
    }
    
    private void doLines(String data, Graphics canvas) {
        bcUtil bcU = new Bc.bcUtil();
        int[] w = new int[1];
        int[] lt = new int[1];
        
        int width;
        int height;
        int xadd = 0;
        
        double alpha = FAngle / 180 * Math.PI;
        
        // Move the orgin so the entire barcode ends up in the visible region.
        Point orgin = bcU.translateQuad2D(alpha, new Point(FLeft, FTop), new Point(getWidth(), FHeight));
        
        for (int i = 0; i < data.length(); i++) {
            oneBarProps(data.charAt(i), w, lt);
            width = w[0];
            
            if ((lt[0] == TBarLineType.black) || (lt[0] == TBarLineType.black_half))
                canvas.setColor(FColorBar);
            else
                canvas.setColor(FColor);
            
            if (lt[0] == TBarLineType.black_half)
                height = FHeight * 2 / 5;
            else
                height = FHeight;
            
            // a,b,c,d builds the rectangle we want to draw
            Point a = new Point(xadd, 0);
            Point b = new Point(xadd, height);
            Point c = new Point(xadd + width - 1, height);
            Point d = new Point(xadd + width - 1, 0);
            
            // rotate the rectangle}
            a = bcU.translate2D(bcU.rotate2D(a, alpha), orgin);
            b = bcU.translate2D(bcU.rotate2D(b, alpha), orgin);
            c = bcU.translate2D(bcU.rotate2D(c, alpha), orgin);
            d = bcU.translate2D(bcU.rotate2D(d, alpha), orgin);
            
            // draw the rectangle
            Polygon p = new Polygon();
            p.addPoint(a.x, a.y);
            p.addPoint(b.x, b.y);
            p.addPoint(c.x, c.y);
            p.addPoint(d.x, d.y);
            canvas.drawPolygon(p);
            canvas.fillPolygon(p);
            xadd += width;
        }
    }
    
    private String setLen(int pI) {
        int l = pI - FText.length();
        StringBuffer s = new StringBuffer();
        while (s.length() < l)
            s.append('0');
        s.append(FText);
        
        return s.toString();
    }
    
    private String code_2_5_interleaved() {
        return null;
    }
    
    private String code_2_5_industrial() {
        return null;
    }
    
    private String code_2_5_matrix() {
        return null;
    }
    
    private String code_39() {
        return null;
    }
    
    private String code_39Extended() {
        return null;
    }
    
    private String code_128() {
        return null;
    }
    
    private String code_93() {
        return null;
    }
    
    private String code_93Extended() {
        return null;
    }
    
    private String code_MSI() {
        return null;
    }
    
    private String code_PostNet() {
        return null;
    }
    
    private String code_Codabar() {
        return null;
    }
    
    /**
     * function TAsBarcode.Code_EAN8: string;
     * var
     *   i: integer;
     *   tmp: string;
     * begin
     *   if FCheckSum then begin
     *     tmp := SetLen(7);
     *     tmp := DoCheckSumming(copy(tmp, length(tmp) - 6, 7));
     *   end
     *   else
     *     tmp := SetLen(8);
     *
     * {$IFDEF ASSERT_SUPPORTED}
     *   Assert(Length(tmp) = 8, 'Invalid Text len (EAN8)');
     * {$ENDIF}
     *   result := '505'; {Startcode}
     *
     *   for i := 1 to 4 do
     *     result := result + tabelle_EAN_A[tmp[i]];
     *
     *   result := result + '05050'; {Center Guard Pattern}
     *
     *   for i := 5 to 8 do
     *     result := result + tabelle_EAN_C[tmp[i]];
     *
     *   result := result + '505'; {Stopcode}
     * end;
     *
     */
    private String code_EAN8()
    throws Exception {
        String tmp;
        if (FCheckSum)
            tmp = doCheckSumming(setLen(7));
        else
            tmp = setLen(8);
        
        if (tmp.length() != 8)
            throw new Exception("Invalid Text len (EAN8)");
        
        StringBuffer result = new StringBuffer("505");
        
        for (int i = 0; i < 4; i++) {
            result.append(tabelle_EAN_A[Integer.valueOf(tmp.substring(i, i + 1)).intValue()]);
        }
        
        result.append("05050"); // Center Guard Pattern
        
        for (int i = 4; i < 8; i++)
            result.append(tabelle_EAN_C[Integer.valueOf(tmp.substring(i, i + 1)).intValue()]);
        
        result.append("505"); // StopCode
        return result.toString();
    }
    
    private String code_EAN13() {
        return null;
    }
    
    private String code_UPC_A() {
        return null;
    }
    
    private String code_UPC_E0() {
        return null;
    }
    
    private String code_UPC_E1() {
        return null;
    }
    
    private String code_Supp5() {
        return null;
    }
    
    private String code_Supp2() {
        return null;
    }
    
    public String getTypeText() {
        return BcData[FType].getName();
    }
    
    /**
     * procedure TAsBarcode.MakeModules;
     * begin
     *   case Typ of
     *     bcCode_2_5_interleaved,
     *       bcCode_2_5_industrial,
     *       bcCode39,
     *       bcCodeEAN8,
     *       bcCodeEAN13,
     *       bcCode39Extended,
     *       bcCodeCodabar,
     *       bcCodeUPC_A,
     *       bcCodeUPC_E0,
     *       bcCodeUPC_E1,
     *       bcCodeUPC_Supp2,
     *       bcCodeUPC_Supp5:
     *       begin
     *         if Ratio < 2.0 then Ratio := 2.0;
     *         if Ratio > 3.0 then Ratio := 3.0;
     *       end;
     *
     *     bcCode_2_5_matrix: begin
     *         if Ratio < 2.25 then Ratio := 2.25;
     *         if Ratio > 3.0 then Ratio := 3.0;
     *       end;
     *     bcCode128A,
     *       bcCode128B,
     *       bcCode128C,
     *       bcCode93,
     *       bcCode93Extended,
     *       bcCodeMSI,
     *       bcCodePostNet: ;
     *   end;
     *
     *   modules[0] := FModul;
     *   modules[1] := Round(FModul * FRatio);
     *   modules[2] := modules[1] * 3 div 2;
     *   modules[3] := modules[1] * 2;
     * end;
     *
     */
    private void makeModules() {
        switch (FType) {
            case TBarcodeType.bcCode_2_5_interleaved:
            case TBarcodeType.bcCode_2_5_industrial:
            case TBarcodeType.bcCode39:
            case TBarcodeType.bcCodeEAN8:
            case TBarcodeType.bcCodeEAN13:
            case TBarcodeType.bcCode39Extended:
            case TBarcodeType.bcCodeCodabar:
            case TBarcodeType.bcCodeUPC_A:
            case TBarcodeType.bcCodeUPC_E0:
            case TBarcodeType.bcCodeUPC_E1:
            case TBarcodeType.bcCodeUPC_Supp2:
            case TBarcodeType.bcCodeUPC_Supp5:
                if (FRatio < 2)
                    FRatio = 2;
                if (FRatio > 3.)
                    FRatio = 3.;
                break;
                
            case TBarcodeType.bcCode_2_5_matrix:
                if (FRatio < 2.25)
                    FRatio = 2.25;
                if (FRatio > 3.)
                    FRatio = 3.;
                break;
        }
        modules[0] = FModul;
        modules[1] = FModul * new Double(FRatio).intValue();
        modules[2] = modules[1] * 3 / 2;
        modules[3] = modules[1] * 2;
    }
    
    /**
     * function TAsBarcode.GetWidth: integer;
     * var
     *   data: string;
     *   i: integer;
     *   w: integer;
     *   lt: TBarLineType;
     * begin
     *   Result := 0;
     *
     *   {get barcode pattern}
     *   data := MakeData;
     *
     *   for i := 1 to Length(data) do {examine the pattern string} begin
     *     OneBarProps(data[i], w, lt);
     *     Inc(Result, w);
     *   end;
     * end;
     */
    public int getWidth() {
        int res = 0;
        int[] w = new int[1];
        w[0] = 0;
        int[] lt = new int[1];
        try {
            // get barcode pattern
            String data = makeData();
            
            // examine the pattern string
            for (int i = 0; i < data.length(); i++) {
                oneBarProps(data.charAt(i), w, lt);
                res = res + w[0];
            }
            return res;
        }
        catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }
    
    /**
     *
     * procedure TAsBarcode.SetWidth(Value: integer);
     * var
     *   data: string;
     *   i: integer;
     *   w, wtotal: integer;
     *   lt: TBarLineType;
     * begin
     *   wtotal := 0;
     *
     *   {get barcode pattern}
     *   data := MakeData;
     *
     *   for i := 1 to Length(data) do {examine the pattern string} begin
     *     OneBarProps(data[i], w, lt);
     *     Inc(wtotal, w);
     *   end;
     *
     *   {
     *   wtotal:  current width of barcode
     *   Value :  new width of barcode
     *
     *   }
     *
     *   if wtotal > 0 then { don't divide by 0 ! }
     *     SetModul((FModul * Value) div wtotal);
     * end;
     */
    public void setWidth(int Value) {
        int wtotal = 0;
        int[] w = new int[1];
        w[0] = 0;
        int[] lt = new int[1];
        
        try {
            // get barcode pattern
            String data = makeData();
            
            for (int i = 1; i < data.length(); i++) {
                oneBarProps(data.charAt(i), w, lt);
                wtotal = wtotal + w[0];
            }
            
            // wtotal:  current width of barcode
            // Value :  new width of barcode
            if (wtotal > 0)
                setModul((FModul * Value) / wtotal);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    /**
     * function TAsBarcode.DoCheckSumming(const data: string): string;
     * begin
     *   case FCheckSumMethod of
     *
     *     csmNone:
     *       Result := data;
     *     csmModulo10:
     *       Result := CheckSumModulo10(data);
     *
     *   end;
     * end;
     */
    private String doCheckSumming(final String data) {
        switch (FCheckSumMethod) {
            case TCheckSumMethod.csmNone: return data;
            case TCheckSumMethod.csmModulo10: return checkSumModulo10(data);
            default: return null;
        }
    }
    
    /**
     * function CheckSumModulo10(const data:string):string;
     * 	var i,fak,sum : Integer;
     * begin
     * 	sum := 0;
     * 	fak := Length(data);
     * 	for i:=1 to Length(data) do
     * 	begin
     * 	  if (fak mod 2) = 0 then
     * 	    sum := sum + (StrToInt(data[i])*1)
     * 	  else
     * 	    sum := sum + (StrToInt(data[i])*3);
     * 	  dec(fak);
     * 	end;
     * 	if (sum mod 10) = 0 then
     * 	  result := data+'0'
     * 	else
     * 	  result := data+IntToStr(10-(sum mod 10));
     * end;
     *
     */
    private String checkSumModulo10(final String data) {
        int sum = 0;
        int fak = data.length();
        byte[] bData = data.getBytes();
        
        for (int i = 0; i < data.length(); i++) {
            if (fak % 2 == 0)
                sum += bData[i] * 1;
            else
                sum += bData[i] * 3;
            fak--;
        }
        
        if (sum % 10 == 0)
            return data + "0";
        else
            return data + (10 - (sum % 10));
    }
    
    public void setType(final int Value) {
        if (Value != FType) {
            int oldTyp = Value;
            FType = Value;
            propertyChangeSupport.firePropertyChange("setTyp", new Integer(oldTyp), new Integer(FType));
        }
    }
    
    public void setAngle(final double Value) {
        if (Value != FAngle) {
            double oldAngle = Value;
            FAngle = Value;
            propertyChangeSupport.firePropertyChange("setAngle", new Double(oldAngle), new Double(FAngle));
        }
    }
    
    public void setText(final String Value) {
        if (Value != FText) {
            String oldText = Value;
            FText = Value;
            propertyChangeSupport.firePropertyChange("setText", new String(oldText), new String(FText));
        }
    }
    
    private void setShowText(final TBarcodeOption Value) {
        
    }
    
    private void setTop(final int Value) {
        
    }
    
    private void setLeft(final int Value) {
        
    }
    
    public void setCheckSum(final boolean Value) {
        if (Value != FCheckSum) {
            boolean oldCheckSum = Value;
            FCheckSum = Value;
            propertyChangeSupport.firePropertyChange("setCheckSum", new Boolean(oldCheckSum), new Boolean(FCheckSum));
        }
    }
    
    private void setShowTextFont(final Font Value) {
        
    }
    
    public void paint(Graphics g) {
        try {
            Dimension s = getSize();
            Dimension p = getBarExtents();
            if ((p.height != s.height) || (p.width != s.width))
                setSize(p.width, p.height);

            drawBarcode(g);
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }
    
    private void setShowTextPosition(final TShowTextPosition Value) {
        
    }
    
    /**
     * function TAsBarcode.MakeData: string;
     * var
     *   i: integer;
     * begin
     *   {calculate the with of the different lines (modules)}
     *   MakeModules;
     *
     *   {numeric barcode type ?}
     *   if BCdata[Typ].num then begin
     *     FText := Trim(FText); {remove blanks}
     *     for i := 1 to Length(Ftext) do
     *       if (FText[i] > '9') or (FText[i] < '0') then
     *         raise Exception.Create('Barcode must be numeric');
     *   end;
     *
     *   {get the pattern of the barcode}
     *   case Typ of
     *     bcCode_2_5_interleaved: Result := Code_2_5_interleaved;
     *     bcCode_2_5_industrial: Result := Code_2_5_industrial;
     *     bcCode_2_5_matrix: Result := Code_2_5_matrix;
     *     bcCode39: Result := Code_39;
     *     bcCode39Extended: Result := Code_39Extended;
     *     bcCode128A,
     *       bcCode128B,
     *       bcCode128C,
     *       bcCodeEAN128A,
     *       bcCodeEAN128B,
     *       bcCodeEAN128C: Result := Code_128;
     *     bcCode93: Result := Code_93;
     *     bcCode93Extended: Result := Code_93Extended;
     *     bcCodeMSI: Result := Code_MSI;
     *     bcCodePostNet: Result := Code_PostNet;
     *     bcCodeCodabar: Result := Code_Codabar;
     *     bcCodeEAN8: Result := Code_EAN8;
     *     bcCodeEAN13: Result := Code_EAN13;
     *     bcCodeUPC_A: Result := Code_UPC_A;
     *     bcCodeUPC_E0: Result := Code_UPC_E0;
     *     bcCodeUPC_E1: Result := Code_UPC_E1;
     *     bcCodeUPC_Supp2: Result := Code_Supp2;
     *     bcCodeUPC_Supp5: Result := Code_Supp5;
     *   else
     *     raise Exception.CreateFmt('%s: wrong BarcodeType', [self.ClassName]);
     *   end;
     *
     *   {
     *   Showmessage(Format('Data <%s>', [Result]));
     *   }
     * end;
     */
    protected String makeData()
    throws Exception {
        // calculate the with of the different lines (modules)
        makeModules();
        
        // numeric barcode type ?
        if (BcData[FType].num){
            FText = FText.trim();
            for (int i = 0; i < FText.length(); i++) {
                if ((FText.charAt(i) > '9') || (FText.charAt(i) < '0'))
                    throw new Exception("Barcode have to be numeric");
            }
        }
        
        // get the pattern of the barcode
        switch (FType) {
            case TBarcodeType.bcCode_2_5_interleaved: return code_2_5_interleaved();
            case TBarcodeType.bcCode_2_5_industrial: return code_2_5_industrial();
            case TBarcodeType.bcCode_2_5_matrix: return code_2_5_matrix();
            case TBarcodeType.bcCode39: return code_39();
            case TBarcodeType.bcCode39Extended: return code_39Extended();
            case TBarcodeType.bcCode128A: return code_128();
            case TBarcodeType.bcCode128B: return code_128();
            case TBarcodeType.bcCode128C: return code_128();
            case TBarcodeType.bcCodeEAN128A: return code_128();
            case TBarcodeType.bcCodeEAN128B: return code_128();
            case TBarcodeType.bcCodeEAN128C: return code_128();
            case TBarcodeType.bcCode93: return code_93();
            case TBarcodeType.bcCode93Extended: return code_93Extended();
            case TBarcodeType.bcCodeMSI: return code_MSI();
            case TBarcodeType.bcCodePostNet: return code_PostNet();
            case TBarcodeType.bcCodeCodabar: return code_Codabar();
            case TBarcodeType.bcCodeEAN8: return code_EAN8();
            case TBarcodeType.bcCodeEAN13: return code_EAN13();
            case TBarcodeType.bcCodeUPC_A: return code_UPC_A();
            case TBarcodeType.bcCodeUPC_E0: return code_UPC_E0();
            case TBarcodeType.bcCodeUPC_E1: return code_UPC_E1();
            case TBarcodeType.bcCodeUPC_Supp2: return code_Supp2();
            case TBarcodeType.bcCodeUPC_Supp5: return code_Supp5();
            default:
                throw new Exception("Wrong Barcode type");
        }
    }
    
    /**
     * procedure TAsBarcode.DrawBarcode(Canvas: TCanvas);
     * var
     *   data: string;
     *   SaveFont: TFont;
     *   SavePen: TPen;
     *   SaveBrush: TBrush;
     * begin
     *   Savefont := TFont.Create;
     *   SavePen := TPen.Create;
     *   SaveBrush := TBrush.Create;
     *
     *   {get barcode pattern}
     *   data := MakeData;
     *
     *   try
     *     {store Canvas properties}
     *     Savefont.Assign(Canvas.Font);
     *     SavePen.Assign(Canvas.Pen);
     *     SaveBrush.Assign(Canvas.Brush);
     *
     *     DoLines(data, Canvas); {draw the barcode}
     *
     *     if FShowText <> bcoNone then
     *       DrawText(Canvas); {show readable Text}
     *
     *     {restore old Canvas properties}
     *     Canvas.Font.Assign(savefont);
     *     Canvas.Pen.Assign(SavePen);
     *     Canvas.Brush.Assign(SaveBrush);
     *   finally
     *     Savefont.Free;
     *     SavePen.Free;
     *     SaveBrush.Free;
     *   end;
     * end;
     */
    public void drawBarcode(Graphics canvas)
    throws Exception {
        String data = makeData();
        
        Font saveFon = canvas.getFont();
        Color saveColor = canvas.getColor();
        
        doLines(data, canvas); //draw the barcode
        
        if (FShowText != TBarcodeOption.bcoNone)
            drawText(canvas); //show readable Text
        
        canvas.setColor(saveColor);
        canvas.setFont(saveFon);
        //        setSize(getWidth(), getHeight());
    }
    
    public void drawText(Graphics canvas) {
        
    }
    
    public String getText() {
        return FText;
    }
    
    public int getTop() {
        return FTop;
    }
    
    public int getLeft() {
        return FLeft;
    }
    
    public double getRatio() {
        return FRatio;
    }
    
    public int getType() {
        return FType;
    }
    
    public boolean isCheckSum() {
        return FCheckSum;
    }
    
    public int getCheckSumMethod() {
        return FCheckSumMethod;
    }
    
    public void setCheckSumMethod(int Value) {
        if (FCheckSumMethod != Value) {
            int oldCheckSumMethod = FCheckSumMethod;
            FCheckSumMethod = Value;
            propertyChangeSupport.firePropertyChange("FCheckSumMethod", new Integer(oldCheckSumMethod), new Integer(FCheckSumMethod));
        }    
    }
    
    public double getAngle() {
        return FAngle;
    }
    
    public int getShowText() {
        return FShowText;
    }
    
    public Font getShowTextFont() {
        return FShowTextFont;
    }
    
    public TShowTextPosition getShowTextPosition() {
        return FShowTextPosition;
    }
    
    public Color getColor() {
        return FColor;
    }
    
    public void setColor(Color color) throws java.beans.PropertyVetoException {
        FColor = color;
    }
    
    public Color getColorBar() {
        return FColorBar;
    }
    
    public void setColorBar(Color colorBar) {
        FColorBar = colorBar;
    }
    
    public void addPropertyChangeListener(java.beans.PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }
    
    public void removePropertyChangeListener(java.beans.PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }
    
    public void setModul(int v) {
        if ((v >= 1) && (v < 50)) {
            int oldModul = FModul;
            FModul = v;
            propertyChangeSupport.firePropertyChange("FModul", new Integer(oldModul), new Integer(FModul));
        }
    }
    
    public void setRatio(final double Value) {
        if (FRatio != Value) {
            double oldRatio = FRatio;
            FRatio = Value;
            propertyChangeSupport.firePropertyChange("FRatio", new Double(oldRatio), new Double(FRatio));
        }
        
    }
    
    public void setHeightBar(final int Value) {
        if (FHeight != Value) {
            int oldHeight = FHeight;
            FHeight = Value;
            propertyChangeSupport.firePropertyChange("FHeight", new Integer(oldHeight), new Integer(FHeight));
        }
        
    }
    
    public int getModul() {
        return FModul;
    }
    
    public int getHeightBar() {
        return FHeight;
    }
    
    public void setShowText(int Value) {
        if (FShowText != Value) {
            int oldShowText = FShowText;
            FShowText = Value;
            propertyChangeSupport.firePropertyChange("FShowText", new Integer(oldShowText), new Integer(FShowText));
        }}
    
    public Dimension getMinimumSize() {
        return getBarExtents();
    }
    
    public Dimension getPreferredSize() {
        return getMinimumSize();
    }
    
    public String getName() {
        return "Barcode";
    }
    
    private void initComponents() {//GEN-BEGIN:initComponents
        jPanel1 = new javax.swing.JPanel();

        setLayout(new java.awt.BorderLayout());

        jPanel1.setLayout(null);

        add(jPanel1, java.awt.BorderLayout.CENTER);

    }//GEN-END:initComponents
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel jPanel1;
    // End of variables declaration//GEN-END:variables
    
}
