/**
 * @test
 * @summary Test behavior of isJavaIdentifierXX, testIsJavaLetter, and
 *  testIsJavaLetterOrDigit methods for all code points.
 * @bug 8218915
 */
import java.util.List;
import java.util.ArrayList;

public class TestIsJavaIdentifierMethods {

    // List of new code points are not present in Unicode 6.2.
    private static final List<Integer> UNASSIGNED_CODEPOINTS_IN_6_2 = new ArrayList<Integer>() {

        {
            // NORDIC MARK SIGN
            add(0x20BB);
            // MANAT SIGN
            add(0x20BC);
            // RUBLE SIGN
            add(0x20BD);
            // LARI SIGN
            add(0x20BE);
            // BITCOIN SIGN
            add(0x20BF);
            // SQUARE ERA NAME NEWERA
            add(0x32FF);
        }
    };

    public static void main(String[] args) {
        testIsJavaIdentifierPart_int();
        testIsJavaIdentifierPart_char();
        testIsJavaIdentifierStart_int();
        testIsJavaIdentifierStart_char();
        testIsJavaLetter();
        testIsJavaLetterOrDigit();
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierPart(int
     * codePoint), A character may be part of a Java identifier if any of the
     * following are true:
     *

     *
it is a letter

     *
it is a currency symbol (such as '$')

     *
it is a connecting punctuation character (such as '_')
     *

     *
it is a digit

     *
it is a numeric letter (such as a Roman numeral character)

     *
it is a combining mark

     *
it is a non-spacing mark

     *
isIdentifierIgnorable returns true for the
     * character

     *

     * All code points from (0x0000..0x10FFFF) are tested.
     */
    public static void testIsJavaIdentifierPart_int() {
        for (int cp = 0; cp <= Character.MAX_CODE_POINT; cp++) {
            boolean expected = false;
            // Since Character.isJavaIdentifierPart(int) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(cp)) {
                byte type = (byte) Character.getType(cp);
                expected = Character.isLetter(cp) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(cp) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(cp);
            }
            if (Character.isJavaIdentifierPart(cp) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierPart(int) failed for codepoint " + Integer.toHexString(cp));
            }
        }

/**
     * Assertion testing for public static boolean isJavaIdentifierPart(char
     * ch), A character may be part of a Java identifier if any of the
     * following are true:
     *

     *
it is a letter;
     *
it is a currency symbol (such as "$");
     *
it is a connecting punctuation character (such as "_");
     *
it is a digit;
     *
it is a numeric letter (such as a Roman numeral character);
     *
it is a combining mark;
     *
it is a non-spacing mark;
     *
isIdentifierIgnorable returns true for the character.
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaIdentifierPart_char() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaIdentifierPart(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(ch) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(ch);
            }
            if (Character.isJavaIdentifierPart((char) i) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierPart(char) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierStart(int
     * codePoint), A character may start a Java identifier if and only if it is
     * one of the following:
     *

     *
it is a letter;

     *
getType(ch) returns LETTER_NUMBER;

     *
it is a currency symbol (such as "$");

     *
it is a connecting punctuation character (such as "_");

     *

     * All Code points from (0x0000..0x10FFFF) are tested.
     */
    public static void testIsJavaIdentifierStart_int() {
        for (int cp = 0; cp <= Character.MAX_CODE_POINT; cp++) {
            boolean expected = false;
            // Since Character.isJavaIdentifierStart(int) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(cp)) {
                byte type = (byte) Character.getType(cp);
                expected = Character.isLetter(cp) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaIdentifierStart(cp) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierStart(int) failed for codepoint " + Integer.toHexString(cp));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierStart(char),
     * A character may start a Java identifier if and only if it is
     * one of the following:
     *

     *
it is a letter;

     *
getType(ch) returns LETTER_NUMBER;

     *
it is a currency symbol (such as "$");

     *
it is a connecting punctuation character (such as "_");

     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaIdentifierStart_char() {
        for (int i = 0; i <= Character.MAX_VALUE; i++) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaIdentifierStart(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaIdentifierStart(ch) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierStart(char) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaLetter(char ch), A
     * character may start a Java identifier if and only if one of the
     * following is true:
     *

     *
isLetter(ch) returns true
     *
getType(ch) returns LETTER_NUMBER
     *
ch is a currency symbol (such as "$")
     *
ch is a connecting punctuation character (such as "_").
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaLetter() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaLetter(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaLetter(ch) != expected) {
                throw new RuntimeException("Character.isJavaLetter(ch) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaLetterOrDigit(char
     * ch), A character may be part of a Java identifier if and only if any
     *  of the following are true:
     *

     *
it is a letter
     *
it is a currency symbol (such as '$')
     *
it is a connecting punctuation character (such as '_')
     *
it is a digit
     *
it is a numeric letter (such as a Roman numeral character)
     *
it is a combining mark
     *
it is a non-spacing mark
     *
isIdentifierIgnorable returns true for the character.
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaLetterOrDigit() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaLetterOrDigit(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(ch) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(ch);
            }
            if (Character.isJavaLetterOrDigit(ch) != expected) {
                throw new RuntimeException("Character.isJavaLetterOrDigit(ch) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }
}


/**
 * @test
 * @summary Test behavior of isJavaIdentifierXX, testIsJavaLetter, and
 *  testIsJavaLetterOrDigit methods for all code points.
 * @bug 8218915
 */
import java.util.List;
import java.util.ArrayList;

public class TestIsJavaIdentifierMethods {

    // List of new code points are not present in Unicode 6.2.
    private static final List<Integer> UNASSIGNED_CODEPOINTS_IN_6_2 = new ArrayList<Integer>() {

        {
            // NORDIC MARK SIGN
            add(0x20BB);
            // MANAT SIGN
            add(0x20BC);
            // RUBLE SIGN
            add(0x20BD);
            // LARI SIGN
            add(0x20BE);
            // BITCOIN SIGN
            add(0x20BF);
            // SQUARE ERA NAME NEWERA
            add(0x32FF);
        }
    };

    public static void main(String[] args) {
        testIs

testIsJavaIdentifierPart_char();
        testIsJavaIdentifierStart_int();
        testIsJavaIdentifierStart_char();
        testIsJavaLetter();
        testIsJavaLetterOrDigit();
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierPart(int
     * codePoint), A character may be part of a Java identifier if any of the
     * following are true:
     *

     *
it is a letter

     *
it is a currency symbol (such as '$')

     *
it is a connecting punctuation character (such as '_')
     *

     *
it is a digit

     *
it is a numeric letter (such as a Roman numeral character)

     *
it is a combining mark

     *
it is a non-spacing mark

     *
isIdentifierIgnorable returns true for the
     * character

     *

     * All code points from (0x0000..0x10FFFF) are tested.
     */
    public static void testIsJavaIdentifierPart_int() {
        for (int cp = 0; cp <= Character.MAX_CODE_POINT; cp++) {
            boolean expected = false;
            // Since Character.isJavaIdentifierPart(int) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(cp)) {
                byte type = (byte) Character.getType(cp);
                expected = Character.isLetter(cp) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(cp) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(cp);
            }
            if (Character.isJavaIdentifierPart(cp) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierPart(int) failed for codepoint " + Integer.toHexString(cp));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierPart(char
     * ch), A character may be part of a Java identifier if any of the
     * following are true:
     *

     *
it is a letter;
     *
it is a currency symbol (such as "$");
     *
it is a connecting punctuation character (such as "_");
     *
it is a digit;
     *
it is a numeric letter (such as a Roman numeral character);
     *
it is a combining mark;
     *
it is a non-spacing mark;
     *
isIdentifierIgnorable returns true for the character.
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaIdentifierPart_char() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaIdentifierPart(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(ch) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(ch);
            }
            if (Character.isJavaIdentifierPart((char) i) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierPart(char) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierStart(int
     * codePoint), A character may start a Java identifier if and only if it is
     * one of the following:
     *

     *
it is a letter;

     *
getType(ch) returns LETTER_NUMBER;

     *
it is a currency symbol (such as "$");

     *
it is a connecting punctuation character (such as "_");

     *

     * All Code points from (0x0000..0x10FFFF) are tested.
     */
    public static void testIsJavaIdentifierStart_int() {
        for (int cp = 0; cp <= Character.MAX_CODE_POINT; cp++) {
            boolean expected = false;
            // Since Character.isJavaIdentifierStart(int) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(cp)) {
                byte type = (byte) Character.getType(cp);
                expected = Character.isLetter(cp) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaIdentifierStart(cp) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierStart(int) failed for codepoint " + Integer.toHexString(cp));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierStart(char),
     * A character may start a Java identifier if and only if it is
     * one of the following:
     *

     *
it is a letter;

     *
getType(ch) returns LETTER_NUMBER;

     *
it is a currency symbol (such as "$");

     *
it is a connecting punctuation character (such as "_");

     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaIdentifierStart_char() {
        for (int i = 0; i <= Character.MAX_VALUE; i++) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaIdentifierStart(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaIdentifierStart(ch) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierStart(char) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaLetter(char ch), A
     * character may start a Java identifier if and only if one of the
     * following is true:
     *

     *
isLetter(ch) returns true
     *
getType(ch) returns LETTER_NUMBER
     *
ch is a currency symbol (such as "$")
     *
ch is a connecting punctuation character (such as "_").
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaLetter() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaLetter(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaLetter(ch) != expected) {
                throw new RuntimeException("Character.isJavaLetter(ch) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaLetterOrDigit(char
     * ch), A character may be part of a Java identifier if and only if any
     *  of the following are true:
     *

     *
it is a letter
     *
it is a currency symbol (such as '$')
     *
it is a connecting punctuation character (such as '_')
     *
it is a digit
     *
it is a numeric letter (such as a Roman numeral character)
     *
it is a combining mark
     *
it is a non-spacing mark
     *
isIdentifierIgnorable returns true for the character.
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaLetterOrDigit() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaLetterOrDigit(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(ch) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(ch);
            }
            if (Character.isJavaLetterOrDigit(ch) != expected) {
                throw new RuntimeException("Character.isJavaLetterOrDigit(ch) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }
}


if (Character.isJavaLetterOrDigit(ch) != expected) {
                throw new RuntimeException("Character.isJavaLetterOrDigit(ch) failed for codepoint " + Integer.toHexString(i));
            }

/**
 * @test
 * @summary Test behavior of isJavaIdentifierXX, testIsJavaLetter, and
 *  testIsJavaLetterOrDigit methods for all code points.
 * @bug 8218915
 */
import java.util.List;
import java.util.ArrayList;

public class TestIsJavaIdentifierMethods {

    // List of new code points are not present in Unicode 6.2.
    private static final List<Integer> UNASSIGNED_CODEPOINTS_IN_6_2 = new ArrayList<Integer>() {

        {
            // NORDIC MARK SIGN
            add(0x20BB);
            // MANAT SIGN
            add(0x20BC);
            // RUBLE SIGN
            add(0x20BD);
            // LARI SIGN
            add(0x20BE);
            // BITCOIN SIGN
            add(0x20BF);
            // SQUARE ERA NAME NEWERA
            add(0x32FF);
        }
    };

    public static void main(String[] args) {
        testIsJavaIdentifierPart_int();
        testIsJavaIdentifierPart_char();
        testIsJavaIdentifierStart_int();
        testIsJavaIdentifierStart_char();
        testIsJavaLetter();
        testIsJavaLetterOrDigit();
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierPart(int
     * codePoint), A character may be part of a Java identifier if any of the
     * following are true:
     *

     *
it is a letter

     *
it is a currency symbol (such as '$')

     *
it is a connecting punctuation character (such as '_')
     *

     *
it is a digit

     *
it is a numeric letter (such as a Roman numeral character)

     *
it is a combining mark

     *
it is a non-spacing mark

     *
isIdentifierIgnorable returns true for the
     * character

     *

     * All code points from (0x0000..0x10FFFF) are tested.
     */
    public static void testIsJavaIdentifierPart_int() {
        for (int cp = 0; cp <= Character.MAX_CODE_POINT; cp++) {
            boolean expected = false;
            // Since Character.isJavaIdentifierPart(int) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(cp)) {
                byte type = (byte) Character.getType(cp);
                expected = Character.isLetter(cp) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(cp) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(cp);
            }
            if (Character.isJavaIdentifierPart(cp) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierPart(int) failed for codepoint " + Integer.toHexString(cp));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierPart(char
     * ch), A character may be part of a Java identifier if any of the
     * following are true:
     *

     *
it is a letter;
     *
it is a currency symbol (such as "$");
     *
it is a connecting punctuation character (such as "_");
     *
it is a digit;
     *
it is a numeric letter (such as a Roman numeral character);
     *
it is a combining mark;
     *
it is a non-spacing mark;
     *
isIdentifierIgnorable returns true for the character.
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaIdentifierPart_char() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaIdentifierPart(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(ch) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(ch);
            }
            if (Character.isJavaIdentifierPart((char) i) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierPart(char) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierStart(int
     * codePoint), A character may start a Java identifier if and only if it is
     * one of the following:
     *

     *
it is a letter;

     *
getType(ch) returns LETTER_NUMBER;

     *
it is a currency symbol (such as "$");

     *
it is a connecting punctuation character (such as "_");

     *

     * All Code points from (0x0000..0x10FFFF) are tested.
     */
    public static void testIsJavaIdentifierStart_int() {
        for (int cp = 0; cp <= Character.MAX_CODE_POINT; cp++) {
            boolean expected = false;
            // Since Character.isJavaIdentifierStart(int) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(cp)) {
                byte type = (byte) Character.getType(cp);
                expected = Character.isLetter(cp) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaIdentifierStart(cp) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierStart(int) failed for codepoint " + Integer.toHexString(cp));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaIdentifierStart(char),
     * A character may start a Java identifier if and only if it is
     * one of the following:
     *

     *
it is a letter;

     *
getType(ch) returns LETTER_NUMBER;

     *
it is a currency symbol (such as "$");

     *
it is a connecting punctuation character (such as "_");

     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaIdentifierStart_char() {
        for (int i = 0; i <= Character.MAX_VALUE; i++) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaIdentifierStart(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaIdentifierStart(ch) != expected) {
                throw new RuntimeException("Character.isJavaIdentifierStart(char) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaLetter(char ch), A
     * character may start a Java identifier if and only if one of the
     * following is true:
     *

     *
isLetter(ch) returns true
     *
getType(ch) returns LETTER_NUMBER
     *
ch is a currency symbol (such as "$")
     *
ch is a connecting punctuation character (such as "_").
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaLetter() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaLetter(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.LETTER_NUMBER || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION;
            }
            if (Character.isJavaLetter(ch) != expected) {
                throw new RuntimeException("Character.isJavaLetter(ch) failed for codepoint " + Integer.toHexString(i));
            }
        }
    }

    /**
     * Assertion testing for public static boolean isJavaLetterOrDigit(char
     * ch), A character may be part of a Java identifier if and only if any
     *  of the following are true:
     *

     *
it is a letter
     *
it is a currency symbol (such as '$')
     *
it is a connecting punctuation character (such as '_')
     *
it is a digit
     *
it is a numeric letter (such as a Roman numeral character)
     *
it is a combining mark
     *
it is a non-spacing mark
     *
isIdentifierIgnorable returns true for the character.
     *

     * All Unicode code points in the BMP (0x0000..0xFFFF) are tested.
     */
    public static void testIsJavaLetterOrDigit() {
        for (int i = 0; i <= Character.MAX_VALUE; ++i) {
            char ch = (char) i;
            boolean expected = false;
            // Since Character.isJavaLetterOrDigit(char) strictly conforms to
            // character information from version 6.2 of the Unicode Standard,
            // check if code point is in "UNASSIGNED_CODEPOINTS_IN_6_2"
            // list. If the code point is found in list
            // "UNASSIGNED_CODEPOINTS_IN_6_2", value of variable
            if (!UNASSIGNED_CODEPOINTS_IN_6_2.contains(i)) {
                byte type = (byte) Character.getType(ch);
                expected = Character.isLetter(ch) || type == Character.CURRENCY_SYMBOL || type == Character.CONNECTOR_PUNCTUATION || Character.isDigit(ch) || type == Character.LETTER_NUMBER || type == Character.COMBINING_SPACING_MARK || type == Character.NON_SPACING_MARK || Character.isIdentifierIgnorable(ch);
            }


public static int parseMultiplierForImport(String multiplier)

package org.openlowcode.server.data;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.openlowcode.module.system.data.choice.ApplocaleChoiceDefinition;
import org.openlowcode.server.data.loader.FlatFileExtractor;
import org.openlowcode.server.data.loader.FlatFileLoader;
import org.openlowcode.server.data.loader.FlatFileLoaderColumn;
import org.openlowcode.server.data.loader.PostUpdateProcessingStore;

public class DecimalDataObjectFieldFlatFileLoaderColumn<E extends DataObject<E>> extends FlatFileLoaderColumn<E> {

    private static Logger logger = Logger.getLogger(DecimalDataObjectFieldFlatFileLoaderColumn.class.getName());

    private String name;

    private int scale;

    private int precision;

    @SuppressWarnings("unused")
    private ChoiceValue<ApplocaleChoiceDefinition> locale;

    public BigDecimal multiplyatexport = new BigDecimal(1);

    public static class DecimalParser {

        private int scale;

        private int precision;

        private ChoiceValue<ApplocaleChoiceDefinition> locale;

        private DecimalFormat decimalformat;

        private int specialtreatment;

        public static int SPECIAL_TREATMENT_NONE = 0;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_1000 = 1;

        public static int SPECIAL_TREATMENT_DIVIDE_BY_1000 = 2;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_100 = 3;

        public int getSpecialTreatment() {
            return this.specialtreatment;
        }

        /**
         * creates a decimal parser
         *
         * @param scale     digits to the right of decimal point (e.g. 533.33 has
         *                  precision on 2)
         * @param precision total number of digits of the number (e.g. 533.33 is 5
         *                  digits)
         * @param locale    locale if CSV import
         */
        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int specialtreatment) {
            this.scale = scale;
            this.precision = precision;
            this.locale = locale;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.US);
            if (this.locale != null)
                if (this.locale.getStorageCode().equals(ApplocaleChoiceDefinition.get().FR))
                    ;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.FRENCH);
            decimalformat.setParseBigDecimal(true);
            this.specialtreatment = specialtreatment;
        }

        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
            this(scale, precision, locale, SPECIAL_TREATMENT_NONE);
        }

        public BigDecimal parse(String value) {
            try {
                BigDecimal decimal = null;
                if (value != null)
                    if (value.length() > 0) {
                        Number number = decimalformat.parse(value);
                        decimal = (BigDecimal) number;
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_1000)
                            decimal = decimal.multiply(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_DIVIDE_BY_1000)
                            decimal = decimal.divide(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_100)
                            decimal = decimal.multiply(new BigDecimal(100));
                    }
                if (decimal != null)
                    if (decimal.scale() > scale) {
                        decimal = decimal.setScale(scale, RoundingMode.HALF_DOWN);
                    }
                if (decimal != null)
                    if (decimal.precision() > precision)
                        throw new RuntimeException("bad format for big decimal, precision is longer than limit " + precision + " for value " + decimal);
                return decimal;
            } catch (ParseException e) {
                throw new RuntimeException("data is supposed to be big decimal but received the following error when parsing '" + value + "'. Exception " + e.getMessage());
            }
        }
    }

    private DecimalParser decimalparser;

    public static BigDecimal parsemultiplierForExport(String multiplier) {
        if (multiplier == null)
            return new BigDecimal(1);
        if (multiplier.length() == 0)
            return new BigDecimal(1);
        if (multiplier.trim().equals("M1000"))
            return new BigDecimal("0.001");
        if (multiplier.trim().equals("M100"))
            return new BigDecimal("0.01");
        if (multiplier.trim().equals("D1000"))
            return new BigDecimal("1000");
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

{
        if (multiplier == null)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.length() == 0)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.trim().equals("M1000"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
        if (multiplier.trim().equals("M100"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
        if (multiplier.trim().equals("D1000"))
            return DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public DecimalDataObjectFieldFlatFileLoaderColumn(DataObjectDefinition<E> definition, String[] arguments, String name, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
        this.scale = scale;
        this.precision = precision;
        this.name = name;
        this.locale = locale;
        int modifier = DecimalParser.SPECIAL_TREATMENT_NONE;
        if (arguments != null)
            if (arguments.length == 1) {
                String multiplier = arguments[0];
                if (multiplier.trim().equals("M1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
                    multiplyatexport = new BigDecimal("0.001");
                }
                if (multiplier.trim().equals("M100")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M100");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
                    multiplyatexport = new BigDecimal("0.01");
                }
                if (multiplier.trim().equals("D1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of D1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
                    multiplyatexport = new BigDecimal("1000");
                }
                if (modifier == DecimalParser.SPECIAL_TREATMENT_NONE)
                    throw new RuntimeException("Decimal DataObjectFieldFlatFileLoader invalid modifier " + multiplier);
            }
        if (arguments != null)
            if (arguments.length > 1)
                throw new RuntimeException("Decimal DataObjetFieldFlatFileLoader only supports 1 modifier ( M100, M1000 or D1000)");
        decimalparser = new DecimalParser(scale, precision, locale, modifier);
    }

    @Override
    public boolean load(E object, Object value, PostUpdateProcessingStore<E> postupdateprocessingstore) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = object.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + object.getName());
        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) object.payload.lookupSimpleFieldOnName(name);
        BigDecimal oldbigdecimal = decimalfield.getValue();
        BigDecimal newbigdecimal = FlatFileLoader.parseDecimal(value, precision, scale, "Flat file loader for column " + decimalfield.getName(), decimalparser);
        if (FlatFileLoader.isTheSame(oldbigdecimal, newbigdecimal)) {
            return false;
        } else {
            decimalfield.setValue(newbigdecimal);
            return true;
        }
    }

    @Override
    protected boolean putContentInCell(E currentobject, Cell cell, String context) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = currentobject.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + currentobject.getName());
        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) currentobject.payload.lookupSimpleFieldOnName(name);
        BigDecimal decimal = decimalfield.getValue();
        if (decimal != null) {
            decimal = decimal.multiply(this.multiplyatexport);
            cell.setCellValue(decimal.doubleValue());
        }
        if (this.decimalparser.getSpecialTreatment() == DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100) {
            logger.finest("special treatment for cell percentage");
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * puts a big decimal in cell, formatting as percentage if needed
     *
     * @param cell       cell
     * @param value      value
     * @param multiplier multiplier in the sense of DecimalFlatFileLoader
     * @return true if formatting was done, false if formatting was not done
     */
    public static <F extends FieldChoiceDefinition<F>> boolean putContentInCell(Cell cell, BigDecimal value, String multiplier) {
        BigDecimal multiplierforexport = parsemultiplierForExport(multiplier);
        if (value != null)
            cell.setCellValue(value.multiply(multiplierforexport).doubleValue());
        if (multiplierforexport.equals(new BigDecimal("0.01"))) {
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * gets a BigDecimal from cell
     *
     * @param value           value to parse
     * @param scale           number of digits right of the decimal point (e.g.
     *                        533.33 is 2 digits
     * @param precision       total number of digits of the number (e.g. 533.33 is 5
     *                        digits)
     * @param locale          locale for import from text (comma or dot as decimal)
     * @param modifier        String modifier in the sense of
     *                        DecimalDataObjectFieldFlatFileLoader
     * @param contextforerror context used in exceptions
     * @return
     */
    public static <F extends FieldChoiceDefinition<F>> BigDecimal getContentFromCell(Object value, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int modifier, String contextforerror) {
        return FlatFileLoader.parseDecimal(value, precision, scale, contextforerror, new DecimalParser(scale, precision, locale, modifier));
    }
}


{
        return FlatFileLoader.parseDecimal(value, precision, scale, contextforerror, new DecimalParser(scale, precision, locale, modifier));
    }

package org.openlowcode.server.data;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.openlowcode.module.system.data.choice.ApplocaleChoiceDefinition;
import org.openlowcode.server.data.loader.FlatFileExtractor;
import org.openlowcode.server.data.loader.FlatFileLoader;
import org.openlowcode.server.data.loader.FlatFileLoaderColumn;
import org.openlowcode.server.data.loader.PostUpdateProcessingStore;

public class DecimalDataObjectFieldFlatFileLoaderColumn<E extends DataObject<E>> extends FlatFileLoaderColumn<E> {

    private static Logger logger = Logger.getLogger(DecimalDataObjectFieldFlatFileLoaderColumn.class.getName());

    private String name;

    private int scale;

    private int precision;

    @SuppressWarnings("unused")
    private ChoiceValue<ApplocaleChoiceDefinition> locale;

    public BigDecimal multiplyatexport = new BigDecimal(1);

    public static class DecimalParser {

        private int scale;

        private int precision;

        private ChoiceValue<ApplocaleChoiceDefinition> locale;

        private DecimalFormat decimalformat;

        private int specialtreatment;

        public static int SPECIAL_TREATMENT_NONE = 0;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_1000 = 1;

        public static int SPECIAL_TREATMENT_DIVIDE_BY_1000 = 2;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_100 = 3;

        public int getSpecialTreatment() {
            return this.specialtreatment;
        }

        /**
         * creates a decimal parser
         *
         * @param scale     digits to the right of decimal point (e.g. 533.33 has
         *                  precision on 2)
         * @param precision total number of digits of the number (e.g. 533.33 is 5
         *                  digits)
         * @param locale    locale if CSV import
         */
        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int specialtreatment) {
            this.scale = scale;
            this.precision = precision;
            this.locale = locale;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.US);
            if (this.locale != null)
                if (this.locale.getStorageCode().equals(ApplocaleChoiceDefinition.get().FR))
                    ;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.FRENCH);
            decimalformat.setParseBigDecimal(true);
            this.specialtreatment = specialtreatment;
        }

        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
            this(scale, precision, locale, SPECIAL_TREATMENT_NONE);
        }

        public BigDecimal parse(String value) {
            try {
                BigDecimal decimal = null;
                if (value != null)
                    if (value.length() > 0) {
                        Number number = decimalformat.parse(value);
                        decimal = (BigDecimal) number;
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_1000)
                            decimal = decimal.multiply(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_DIVIDE_BY_1000)
                            decimal = decimal.divide(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_100)
                            decimal = decimal.multiply(new BigDecimal(100));
                    }
                if (decimal != null)
                    if (decimal.scale() > scale) {
                        decimal = decimal.setScale(scale, RoundingMode.HALF_DOWN);
                    }
                if (decimal != null)
                    if (decimal.precision() > precision)
                        throw new RuntimeException("bad format for big decimal, precision is longer than limit " + precision + " for value " + decimal);
                return decimal;
            } catch (ParseException e) {
                throw new RuntimeException("data is supposed to be big decimal but received the following error when parsing '" + value + "'. Exception " + e.getMessage());
            }
        }
    }

    private DecimalParser decimalparser;

    public static BigDecimal parsemultiplierForExport(String multiplier) {
        if (multiplier == null)
            return new BigDecimal(1);
        if (multiplier.length() == 0)
            return new BigDecimal(1);
        if (multiplier.trim().equals("M1000"))
            return new BigDecimal("0.001");
        if (multiplier.trim().equals("M100"))
            return new BigDecimal("0.01");
        if (multiplier.trim().equals("D1000"))
            return new BigDecimal("1000");
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public static int parseMultiplierForImport(String multiplier) {
        if (multiplier == null)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.length() == 0)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.trim().equals("M1000"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
        if (multiplier.trim().equals("M100"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
        if (multiplier.trim().equals("D1000"))
            return DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public DecimalDataObjectFieldFlatFileLoaderColumn(DataObjectDefinition<E> definition, String[] arguments, String name, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
        this.scale = scale;
        this.precision = precision;
        this.name = name;
        this.locale = locale;
        int modifier = DecimalParser.SPECIAL_TREATMENT_NONE;
        if (arguments != null)
            if (arguments.length == 1) {
                String multiplier = arguments[0];
                if (multiplier.trim().equals("M1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
                    multiplyatexport = new BigDecimal("0.001");
                }
                if (multiplier.trim().equals("M100")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M100");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
                    multiplyatexport = new BigDecimal("0.01");
                }
                if (multiplier.trim().equals("D1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of D1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
                    multiplyatexport = new BigDecimal("1000");
                }
                if (modifier == DecimalParser.SPECIAL_TREATMENT_NONE)
                    throw new RuntimeException("Decimal DataObjectFieldFlatFileLoader invalid modifier " + multiplier);
            }
        if (arguments != null)
            if (arguments.length > 1)
                throw new RuntimeException("Decimal DataObjetFieldFlatFileLoader only supports 1 modifier ( M100, M1000 or D1000)");
        decimalparser = new DecimalParser(scale, precision, locale, modifier);
    }

    @Override
    public boolean load(E object, Object value, PostUpdateProcessingStore<E> postupdateprocessingstore) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = object.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + object.getName());
        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) object.payload.lookupSimpleFieldOnName(name);
        BigDecimal oldbigdecimal = decimalfield.getValue();
        BigDecimal newbigdecimal = FlatFileLoader.parseDecimal(value, precision, scale, "Flat file loader for column " + decimalfield.getName(), decimalparser);
        if (FlatFileLoader.isTheSame(oldbigdecimal, newbigdecimal)) {
            return false;
        } else {
            decimalfield.setValue(newbigdecimal);
            return true;
        }
    }

    @Override
    protected boolean putContentInCell(E currentobject, Cell cell, String context) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = currentobject.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + currentobject.getName());
        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) currentobject.payload.lookupSimpleFieldOnName(name);
        BigDecimal decimal = decimalfield.getValue();
        if (decimal != null) {
            decimal = decimal.multiply(this.multiplyatexport);
            cell.setCellValue(decimal.doubleValue());
        }
        if (this.decimalparser.getSpecialTreatment() == DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100) {
            logger.finest("special treatment for cell percentage");
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * puts a big decimal in cell, formatting as percentage if needed
     *
     * @param cell       cell
     * @param value      value
     * @param multiplier multiplier in the sense of DecimalFlatFileLoader
     * @return true if formatting was done, false if formatting was not done
     */
    public static <F extends FieldChoiceDefinition<F>> boolean putContentInCell(Cell cell, BigDecimal value, String multiplier) {
        BigDecimal multiplierforexport = parsemultiplierForExport(multiplier);
        if (value != null)
            cell.setCellValue(value.multiply(multiplierforexport).doubleValue());
        if (multiplierforexport.equals(new BigDecimal("0.01"))) {
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * gets a BigDecimal from cell
     *
     * @param value           value to parse
     * @param scale           number of digits right of the decimal point (e.g.
     *                        533.33 is 2 digits
     * @param precision       total number of digits of the number (e.g. 533.33 is 5
     *                        digits)
     * @param locale          locale for import from text (comma or dot as decimal)
     * @param modifier        String modifier in the sense of
     *                        DecimalDataObjectFieldFlatFileLoader
     * @param contextforerror context used in exceptions
     * @return
     */
    public static <F extends FieldChoiceDefinition<F>> BigDecimal getContentFromCell(Object value, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int modifier, String contextforerror)


        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = object.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + object.getName());

package org.openlowcode.server.data;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.openlowcode.module.system.data.choice.ApplocaleChoiceDefinition;
import org.openlowcode.server.data.loader.FlatFileExtractor;
import org.openlowcode.server.data.loader.FlatFileLoader;
import org.openlowcode.server.data.loader.FlatFileLoaderColumn;
import org.openlowcode.server.data.loader.PostUpdateProcessingStore;

public class DecimalDataObjectFieldFlatFileLoaderColumn<E extends DataObject<E>> extends FlatFileLoaderColumn<E> {

    private static Logger logger = Logger.getLogger(DecimalDataObjectFieldFlatFileLoaderColumn.class.getName());

    private String name;

    private int scale;

    private int precision;

    @SuppressWarnings("unused")
    private ChoiceValue<ApplocaleChoiceDefinition> locale;

    public BigDecimal multiplyatexport = new BigDecimal(1);

    public static class DecimalParser {

        private int scale;

        private int precision;

        private ChoiceValue<ApplocaleChoiceDefinition> locale;

        private DecimalFormat decimalformat;

        private int specialtreatment;

        public static int SPECIAL_TREATMENT_NONE = 0;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_1000 = 1;

        public static int SPECIAL_TREATMENT_DIVIDE_BY_1000 = 2;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_100 = 3;

        public int getSpecialTreatment() {
            return this.specialtreatment;
        }

        /**
         * creates a decimal parser
         *
         * @param scale     digits to the right of decimal point (e.g. 533.33 has
         *                  precision on 2)
         * @param precision total number of digits of the number (e.g. 533.33 is 5
         *                  digits)
         * @param locale    locale if CSV import
         */
        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int specialtreatment) {
            this.scale = scale;
            this.precision = precision;
            this.locale = locale;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.US);
            if (this.locale != null)
                if (this.locale.getStorageCode().equals(ApplocaleChoiceDefinition.get().FR))
                    ;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.FRENCH);
            decimalformat.setParseBigDecimal(true);
            this.specialtreatment = specialtreatment;
        }

        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
            this(scale, precision, locale, SPECIAL_TREATMENT_NONE);
        }

        public BigDecimal parse(String value) {
            try {
                BigDecimal decimal = null;
                if (value != null)
                    if (value.length() > 0) {
                        Number number = decimalformat.parse(value);
                        decimal = (BigDecimal) number;
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_1000)
                            decimal = decimal.multiply(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_DIVIDE_BY_1000)
                            decimal = decimal.divide(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_100)
                            decimal = decimal.multiply(new BigDecimal(100));
                    }
                if (decimal != null)
                    if (decimal.scale() > scale) {
                        decimal = decimal.setScale(scale, RoundingMode.HALF_DOWN);
                    }
                if (decimal != null)
                    if (decimal.precision() > precision)
                        throw new RuntimeException("bad format for big decimal, precision is longer than limit " + precision + " for value " + decimal);
                return decimal;
            } catch (ParseException e) {
                throw new RuntimeException("data is supposed to be big decimal but received the following error when parsing '" + value + "'. Exception " + e.getMessage());
            }
        }
    }

    private DecimalParser decimalparser;

    public static BigDecimal parsemultiplierForExport(String multiplier) {
        if (multiplier == null)
            return new BigDecimal(1);
        if (multiplier.length() == 0)
            return new BigDecimal(1);
        if (multiplier.trim().equals("M1000"))
            return new BigDecimal("0.001");
        if (multiplier.trim().equals("M100"))
            return new BigDecimal("0.01");
        if (multiplier.trim().equals("D1000"))
            return new BigDecimal("1000");
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public static int parseMultiplierForImport(String multiplier) {
        if (multiplier == null)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.length() == 0)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.trim().equals("M1000"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
        if (multiplier.trim().equals("M100"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
        if (multiplier.trim().equals("D1000"))
            return DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public DecimalDataObjectFieldFlatFileLoaderColumn(DataObjectDefinition<E> definition, String[] arguments, String name, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
        this.scale = scale;
        this.precision = precision;
        this.name = name;
        this.locale = locale;
        int modifier = DecimalParser.SPECIAL_TREATMENT_NONE;
        if (arguments != null)
            if (arguments.length == 1) {
                String multiplier = arguments[0];
                if (multiplier.trim().equals("M1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
                    multiplyatexport = new BigDecimal("0.001");
                }
                if (multiplier.trim().equals("M100")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M100");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
                    multiplyatexport = new BigDecimal("0.01");
                }
                if (multiplier.trim().equals("D1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of D1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
                    multiplyatexport = new BigDecimal("1000");
                }
                if (modifier == DecimalParser.SPECIAL_TREATMENT_NONE)
                    throw new RuntimeException("Decimal DataObjectFieldFlatFileLoader invalid modifier " + multiplier);
            }
        if (arguments != null)
            if (arguments.length > 1)
                throw new RuntimeException("Decimal DataObjetFieldFlatFileLoader only supports 1 modifier ( M100, M1000 or D1000)");
        decimalparser = new DecimalParser(scale, precision, locale, modifier);
    }

    @Override
    public boolean load(E object, Object value, PostUpdateProcessingStore<E> postupdateprocessingstore) {

        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) object.payload.lookupSimpleFieldOnName(name);
        BigDecimal oldbigdecimal = decimalfield.getValue();
        BigDecimal newbigdecimal = FlatFileLoader.parseDecimal(value, precision, scale, "Flat file loader for column " + decimalfield.getName(), decimalparser);
        if (FlatFileLoader.isTheSame(oldbigdecimal, newbigdecimal)) {
            return false;
        } else {
            decimalfield.setValue(newbigdecimal);
            return true;
        }
    }

    @Override
    protected boolean putContentInCell(E currentobject, Cell cell, String context) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = currentobject.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + currentobject.getName());
        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) currentobject.payload.lookupSimpleFieldOnName(name);
        BigDecimal decimal = decimalfield.getValue();
        if (decimal != null) {
            decimal = decimal.multiply(this.multiplyatexport);
            cell.setCellValue(decimal.doubleValue());
        }
        if (this.decimalparser.getSpecialTreatment() == DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100) {
            logger.finest("special treatment for cell percentage");
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * puts a big decimal in cell, formatting as percentage if needed
     *
     * @param cell       cell
     * @param value      value
     * @param multiplier multiplier in the sense of DecimalFlatFileLoader
     * @return true if formatting was done, false if formatting was not done
     */
    public static <F extends FieldChoiceDefinition<F>> boolean putContentInCell(Cell cell, BigDecimal value, String multiplier) {
        BigDecimal multiplierforexport = parsemultiplierForExport(multiplier);
        if (value != null)
            cell.setCellValue(value.multiply(multiplierforexport).doubleValue());
        if (multiplierforexport.equals(new BigDecimal("0.01"))) {
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * gets a BigDecimal from cell
     *
     * @param value           value to parse
     * @param scale           number of digits right of the decimal point (e.g.
     *                        533.33 is 2 digits
     * @param precision       total number of digits of the number (e.g. 533.33 is 5
     *                        digits)
     * @param locale          locale for import from text (comma or dot as decimal)
     * @param modifier        String modifier in the sense of
     *                        DecimalDataObjectFieldFlatFileLoader
     * @param contextforerror context used in exceptions
     * @return
     */
    public static <F extends FieldChoiceDefinition<F>> BigDecimal getContentFromCell(Object value, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int modifier, String contextforerror) {
        return FlatFileLoader.parseDecimal(value, precision, scale, contextforerror, new DecimalParser(scale, precision, locale, modifier));
    }
}


if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) object.payload.lookupSimpleFieldOnName(name);
        BigDecimal oldbigdecimal = decimalfield.getValue();

package org.openlowcode.server.data;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.openlowcode.module.system.data.choice.ApplocaleChoiceDefinition;
import org.openlowcode.server.data.loader.FlatFileExtractor;
import org.openlowcode.server.data.loader.FlatFileLoader;
import org.openlowcode.server.data.loader.FlatFileLoaderColumn;
import org.openlowcode.server.data.loader.PostUpdateProcessingStore;

public class DecimalDataObjectFieldFlatFileLoaderColumn<E extends DataObject<E>> extends FlatFileLoaderColumn<E> {

    private static Logger logger = Logger.getLogger(DecimalDataObjectFieldFlatFileLoaderColumn.class.getName());

    private String name;

    private int scale;

    private int precision;

    @SuppressWarnings("unused")
    private ChoiceValue<ApplocaleChoiceDefinition> locale;

    public BigDecimal multiplyatexport = new BigDecimal(1);

    public static class DecimalParser {

        private int scale;

        private int precision;

        private ChoiceValue<ApplocaleChoiceDefinition> locale;

        private DecimalFormat decimalformat;

        private int specialtreatment;

        public static int SPECIAL_TREATMENT_NONE = 0;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_1000 = 1;

        public static int SPECIAL_TREATMENT_DIVIDE_BY_1000 = 2;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_100 = 3;

        public int getSpecialTreatment() {
            return this.specialtreatment;
        }

        /**
         * creates a decimal parser
         *
         * @param scale     digits to the right of decimal point (e.g. 533.33 has
         *                  precision on 2)
         * @param precision total number of digits of the number (e.g. 533.33 is 5
         *                  digits)
         * @param locale    locale if CSV import
         */
        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int specialtreatment) {
            this.scale = scale;
            this.precision = precision;
            this.locale = locale;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.US);
            if (this.locale != null)
                if (this.locale.getStorageCode().equals(ApplocaleChoiceDefinition.get().FR))
                    ;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.FRENCH);
            decimalformat.setParseBigDecimal(true);
            this.specialtreatment = specialtreatment;
        }

        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
            this(scale, precision, locale, SPECIAL_TREATMENT_NONE);
        }

        public BigDecimal parse(String value) {
            try {
                BigDecimal decimal = null;
                if (value != null)
                    if (value.length() > 0) {
                        Number number = decimalformat.parse(value);
                        decimal = (BigDecimal) number;
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_1000)
                            decimal = decimal.multiply(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_DIVIDE_BY_1000)
                            decimal = decimal.divide(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_100)
                            decimal = decimal.multiply(new BigDecimal(100));
                    }
                if (decimal != null)
                    if (decimal.scale() > scale) {
                        decimal = decimal.setScale(scale, RoundingMode.HALF_DOWN);
                    }
                if (decimal != null)
                    if (decimal.precision() > precision)
                        throw new RuntimeException("bad format for big decimal, precision is longer than limit " + precision + " for value " + decimal);
                return decimal;
            } catch (ParseException e) {
                throw new RuntimeException("data is supposed to be big decimal but received the following error when parsing '" + value + "'. Exception " + e.getMessage());
            }
        }
    }

    private DecimalParser decimalparser;

    public static BigDecimal parsemultiplierForExport(String multiplier) {
        if (multiplier == null)
            return new BigDecimal(1);
        if (multiplier.length() == 0)
            return new BigDecimal(1);
        if (multiplier.trim().equals("M1000"))
            return new BigDecimal("0.001");
        if (multiplier.trim().equals("M100"))
            return new BigDecimal("0.01");
        if (multiplier.trim().equals("D1000"))
            return new BigDecimal("1000");
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public static int parseMultiplierForImport(String multiplier) {
        if (multiplier == null)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.length() == 0)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.trim().equals("M1000"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
        if (multiplier.trim().equals("M100"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
        if (multiplier.trim().equals("D1000"))
            return DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public DecimalDataObjectFieldFlatFileLoaderColumn(DataObjectDefinition<E> definition, String[] arguments, String name, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
        this.scale = scale;
        this.precision = precision;
        this.name = name;
        this.locale = locale;
        int modifier = DecimalParser.SPECIAL_TREATMENT_NONE;
        if (arguments != null)
            if (arguments.length == 1) {
                String multiplier = arguments[0];
                if (multiplier.trim().equals("M1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
                    multiplyatexport = new BigDecimal("0.001");
                }
                if (multiplier.trim().equals("M100")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M100");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
                    multiplyatexport = new BigDecimal("0.01");
                }
                if (multiplier.trim().equals("D1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of D1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
                    multiplyatexport = new BigDecimal("1000");
                }
                if (modifier == DecimalParser.SPECIAL_TREATMENT_NONE)
                    throw new RuntimeException("Decimal DataObjectFieldFlatFileLoader invalid modifier " + multiplier);
            }
        if (arguments != null)
            if (arguments.length > 1)
                throw new RuntimeException("Decimal DataObjetFieldFlatFileLoader only supports 1 modifier ( M100, M1000 or D1000)");
        decimalparser = new DecimalParser(scale, precision, locale, modifier);
    }

    @Override
    public boolean load(E object, Object value, PostUpdateProcessingStore<E> postupdateprocessingstore) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = object.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + object.getName());

        BigDecimal newbigdecimal = FlatFileLoader.parseDecimal(value, precision, scale, "Flat file loader for column " + decimalfield.getName(), decimalparser);
        if (FlatFileLoader.isTheSame(oldbigdecimal, newbigdecimal)) {
            return false;
        } else {
            decimalfield.setValue(newbigdecimal);
            return true;
        }
    }

    @Override
    protected boolean putContentInCell(E currentobject, Cell cell, String context) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = currentobject.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + currentobject.getName());
        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) currentobject.payload.lookupSimpleFieldOnName(name);
        BigDecimal decimal = decimalfield.getValue();
        if (decimal != null) {
            decimal = decimal.multiply(this.multiplyatexport);
            cell.setCellValue(decimal.doubleValue());
        }
        if (this.decimalparser.getSpecialTreatment() == DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100) {
            logger.finest("special treatment for cell percentage");
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * puts a big decimal in cell, formatting as percentage if needed
     *
     * @param cell       cell
     * @param value      value
     * @param multiplier multiplier in the sense of DecimalFlatFileLoader
     * @return true if formatting was done, false if formatting was not done
     */
    public static <F extends FieldChoiceDefinition<F>> boolean putContentInCell(Cell cell, BigDecimal value, String multiplier) {
        BigDecimal multiplierforexport = parsemultiplierForExport(multiplier);
        if (value != null)
            cell.setCellValue(value.multiply(multiplierforexport).doubleValue());
        if (multiplierforexport.equals(new BigDecimal("0.01"))) {
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * gets a BigDecimal from cell
     *
     * @param value           value to parse
     * @param scale           number of digits right of the decimal point (e.g.
     *                        533.33 is 2 digits
     * @param precision       total number of digits of the number (e.g. 533.33 is 5
     *                        digits)
     * @param locale          locale for import from text (comma or dot as decimal)
     * @param modifier        String modifier in the sense of
     *                        DecimalDataObjectFieldFlatFileLoader
     * @param contextforerror context used in exceptions
     * @return
     */
    public static <F extends FieldChoiceDefinition<F>> BigDecimal getContentFromCell(Object value, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int modifier, String contextforerror) {
        return FlatFileLoader.parseDecimal(value, precision, scale, contextforerror, new DecimalParser(scale, precision, locale, modifier));
    }
}


BigDecimal newbigdecimal = FlatFileLoader.parseDecimal(value, precision, scale, "Flat file loader for column " + decimalfield.getName(), decimalparser);
        if (FlatFileLoader.isTheSame(oldbigdecimal, newbigdecimal)) {
            return false;
        } else {
            decimalfield.setValue(newbigdecimal);
            return true;
        }
    }

package org.openlowcode.server.data;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.openlowcode.module.system.data.choice.ApplocaleChoiceDefinition;
import org.openlowcode.server.data.loader.FlatFileExtractor;
import org.openlowcode.server.data.loader.FlatFileLoader;
import org.openlowcode.server.data.loader.FlatFileLoaderColumn;
import org.openlowcode.server.data.loader.PostUpdateProcessingStore;

public class DecimalDataObjectFieldFlatFileLoaderColumn<E extends DataObject<E>> extends FlatFileLoaderColumn<E> {

    private static Logger logger = Logger.getLogger(DecimalDataObjectFieldFlatFileLoaderColumn.class.getName());

    private String name;

    private int scale;

    private int precision;

    @SuppressWarnings("unused")
    private ChoiceValue<ApplocaleChoiceDefinition> locale;

    public BigDecimal multiplyatexport = new BigDecimal(1);

    public static class DecimalParser {

        private int scale;

        private int precision;

        private ChoiceValue<ApplocaleChoiceDefinition> locale;

        private DecimalFormat decimalformat;

        private int specialtreatment;

        public static int SPECIAL_TREATMENT_NONE = 0;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_1000 = 1;

        public static int SPECIAL_TREATMENT_DIVIDE_BY_1000 = 2;

        public static int SPECIAL_TREATMENT_MULTIPLY_BY_100 = 3;

        public int getSpecialTreatment() {
            return this.specialtreatment;
        }

        /**
         * creates a decimal parser
         *
         * @param scale     digits to the right of decimal point (e.g. 533.33 has
         *                  precision on 2)
         * @param precision total number of digits of the number (e.g. 533.33 is 5
         *                  digits)
         * @param locale    locale if CSV import
         */
        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int specialtreatment) {
            this.scale = scale;
            this.precision = precision;
            this.locale = locale;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.US);
            if (this.locale != null)
                if (this.locale.getStorageCode().equals(ApplocaleChoiceDefinition.get().FR))
                    ;
            decimalformat = (DecimalFormat) NumberFormat.getInstance(Locale.FRENCH);
            decimalformat.setParseBigDecimal(true);
            this.specialtreatment = specialtreatment;
        }

        public DecimalParser(int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
            this(scale, precision, locale, SPECIAL_TREATMENT_NONE);
        }

        public BigDecimal parse(String value) {
            try {
                BigDecimal decimal = null;
                if (value != null)
                    if (value.length() > 0) {
                        Number number = decimalformat.parse(value);
                        decimal = (BigDecimal) number;
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_1000)
                            decimal = decimal.multiply(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_DIVIDE_BY_1000)
                            decimal = decimal.divide(new BigDecimal(1000));
                        if (specialtreatment == SPECIAL_TREATMENT_MULTIPLY_BY_100)
                            decimal = decimal.multiply(new BigDecimal(100));
                    }
                if (decimal != null)
                    if (decimal.scale() > scale) {
                        decimal = decimal.setScale(scale, RoundingMode.HALF_DOWN);
                    }
                if (decimal != null)
                    if (decimal.precision() > precision)
                        throw new RuntimeException("bad format for big decimal, precision is longer than limit " + precision + " for value " + decimal);
                return decimal;
            } catch (ParseException e) {
                throw new RuntimeException("data is supposed to be big decimal but received the following error when parsing '" + value + "'. Exception " + e.getMessage());
            }
        }
    }

    private DecimalParser decimalparser;

    public static BigDecimal parsemultiplierForExport(String multiplier) {
        if (multiplier == null)
            return new BigDecimal(1);
        if (multiplier.length() == 0)
            return new BigDecimal(1);
        if (multiplier.trim().equals("M1000"))
            return new BigDecimal("0.001");
        if (multiplier.trim().equals("M100"))
            return new BigDecimal("0.01");
        if (multiplier.trim().equals("D1000"))
            return new BigDecimal("1000");
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public static int parseMultiplierForImport(String multiplier) {
        if (multiplier == null)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.length() == 0)
            return DecimalParser.SPECIAL_TREATMENT_NONE;
        if (multiplier.trim().equals("M1000"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
        if (multiplier.trim().equals("M100"))
            return DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
        if (multiplier.trim().equals("D1000"))
            return DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
        throw new RuntimeException("Invalid multiplier " + multiplier);
    }

    public DecimalDataObjectFieldFlatFileLoaderColumn(DataObjectDefinition<E> definition, String[] arguments, String name, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale) {
        this.scale = scale;
        this.precision = precision;
        this.name = name;
        this.locale = locale;
        int modifier = DecimalParser.SPECIAL_TREATMENT_NONE;
        if (arguments != null)
            if (arguments.length == 1) {
                String multiplier = arguments[0];
                if (multiplier.trim().equals("M1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_1000;
                    multiplyatexport = new BigDecimal("0.001");
                }
                if (multiplier.trim().equals("M100")) {
                    logger.finer(" ---> For field " + name + ", special treatment of M100");
                    modifier = DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100;
                    multiplyatexport = new BigDecimal("0.01");
                }
                if (multiplier.trim().equals("D1000")) {
                    logger.finer(" ---> For field " + name + ", special treatment of D1000");
                    modifier = DecimalParser.SPECIAL_TREATMENT_DIVIDE_BY_1000;
                    multiplyatexport = new BigDecimal("1000");
                }
                if (modifier == DecimalParser.SPECIAL_TREATMENT_NONE)
                    throw new RuntimeException("Decimal DataObjectFieldFlatFileLoader invalid modifier " + multiplier);
            }
        if (arguments != null)
            if (arguments.length > 1)
                throw new RuntimeException("Decimal DataObjetFieldFlatFileLoader only supports 1 modifier ( M100, M1000 or D1000)");
        decimalparser = new DecimalParser(scale, precision, locale, modifier);
    }

    @Override
    public boolean load(E object, Object value, PostUpdateProcessingStore<E> postupdateprocessingstore) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = object.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + object.getName());
        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) object.payload.lookupSimpleFieldOnName(name);
        BigDecimal oldbigdecimal = decimalfield.getValue();

    @Override
    protected boolean putContentInCell(E currentobject, Cell cell, String context) {
        @SuppressWarnings("unchecked")
        DataObjectField<?, E> field = currentobject.payload.lookupSimpleFieldOnName(name);
        if (field == null)
            throw new RuntimeException("field " + name + " could not be looked-up on " + currentobject.getName());
        if (!(field instanceof DecimalDataObjectField))
            throw new RuntimeException("Expected field " + name + " would be of type DecimalDataObjectField but in reality, it is " + field.getClass().toString());
        DecimalDataObjectField<?> decimalfield = (DecimalDataObjectField<?>) currentobject.payload.lookupSimpleFieldOnName(name);
        BigDecimal decimal = decimalfield.getValue();
        if (decimal != null) {
            decimal = decimal.multiply(this.multiplyatexport);
            cell.setCellValue(decimal.doubleValue());
        }
        if (this.decimalparser.getSpecialTreatment() == DecimalParser.SPECIAL_TREATMENT_MULTIPLY_BY_100) {
            logger.finest("special treatment for cell percentage");
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * puts a big decimal in cell, formatting as percentage if needed
     *
     * @param cell       cell
     * @param value      value
     * @param multiplier multiplier in the sense of DecimalFlatFileLoader
     * @return true if formatting was done, false if formatting was not done
     */
    public static <F extends FieldChoiceDefinition<F>> boolean putContentInCell(Cell cell, BigDecimal value, String multiplier) {
        BigDecimal multiplierforexport = parsemultiplierForExport(multiplier);
        if (value != null)
            cell.setCellValue(value.multiply(multiplierforexport).doubleValue());
        if (multiplierforexport.equals(new BigDecimal("0.01"))) {
            CellStyle percentagecellstyle = FlatFileExtractor.createBorderedStyle(cell.getSheet().getWorkbook());
            percentagecellstyle.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("0.0%"));
            cell.setCellStyle(percentagecellstyle);
            return true;
        }
        return false;
    }

    /**
     * gets a BigDecimal from cell
     *
     * @param value           value to parse
     * @param scale           number of digits right of the decimal point (e.g.
     *                        533.33 is 2 digits
     * @param precision       total number of digits of the number (e.g. 533.33 is 5
     *                        digits)
     * @param locale          locale for import from text (comma or dot as decimal)
     * @param modifier        String modifier in the sense of
     *                        DecimalDataObjectFieldFlatFileLoader
     * @param contextforerror context used in exceptions
     * @return
     */
    public static <F extends FieldChoiceDefinition<F>> BigDecimal getContentFromCell(Object value, int scale, int precision, ChoiceValue<ApplocaleChoiceDefinition> locale, int modifier, String contextforerror) {
        return FlatFileLoader.parseDecimal(value, precision, scale, contextforerror, new DecimalParser(scale, precision, locale, modifier));
    }
}