class JavaPropertiesResource extends ResourceFilter {

    static String unescapeMessagePattern(String inputStr, MessagePatternEscape msgPatEsc) throws ResourceFilterException {
        // Quick check - if there are no double apostrophes, skip this operation.
        if (inputStr.indexOf("''") < 0) {
            return inputStr;
        }

        MessagePattern msgPat = new MessagePattern(ApostropheMode.DOUBLE_OPTIONAL);

        try {
            msgPat.parse(inputStr);

            if (msgPatEsc == MessagePatternEscape.AUTO && !hasArgs(msgPat)) {
                // In AUTO mode, a strings is not handled as message format pattern
                // when no arguments are found.

                // TODO: A string like "Can''t delete a file." is most likely a message format
                // pattern without arguments and the implementation can turn it to
                // "Can't delete a file." during import. However, in this case, there is
                // no way to determine whether the apostrophe is emitted as-is, or doubled
                // for export, unless we store the information (whether it was imported as
                // message format pattern or not) separately. Revisit this later.

                return inputStr;
            }
        } catch (Exception e) {
            // This input string cannot be parsed as MessageFormat pattern.
            if (msgPatEsc == MessagePatternEscape.ALL) {
                throw new ResourceFilterException("Illegal message pattern string: " + inputStr);
            }
            // If msgPatEsc is not MessagePatternEscape.ALL, input string does
            // not need to be a valid message pattern. In this case, just return
            // the input as is.
            return inputStr;
        }

        StringBuilder buf = new StringBuilder();
        int start = 0;
        PrevState prev = PrevState.OTHER;
        boolean inQuote = false;

        for (int i = 0; i < msgPat.countParts(); i++) {
            Part part = msgPat.getPart(i);
            int limit = part.getLimit();
            int endIdx = limit;

            Type type = part.getType();
            if (type == Type.ARG_START) {
                // If an argument start *IMMEDIATELY* after doubled apostrophe,
                // this code append the second apostrophe.
                if (prev == PrevState.DEFERRED_APOSTROPHE && (limit - start) == 1) {
                    buf.append("'");
                }
                prev = PrevState.OTHER;
            } else if (type == Type.SKIP_SYNTAX) {
                // Is this skip part a single apostrophe?
                boolean curApos = msgPat.getSubstring(part).equals("'");
                // Preceded by an apostrophe?
                boolean doubleApos = false;
                if (curApos) {
                    // Check character before this skip part.
                    // limit is the index after the skip part,
                    // and limit -1 is the index for this skip part,
                    // so the previous character is at the index of
                    // limit - 2.
                    doubleApos = inputStr.charAt(limit - 2) == '\'';
                }
                if (doubleApos) {
                    boolean emitSecondApos = false;
                    if (inQuote) {
                        // Double apostrophes in a quoted segment are
                        // always emitted as is.
                        emitSecondApos = true;
                        prev = PrevState.OTHER;
                    } else if (prev == PrevState.ARG_LIMIT) {
                        // If previous part was end of argument, and
                        // double apostrophes immediately follow, then
                        // double apostrophes are emitted as is.
                        // Otherwise, defer the decision.
                        if (start == limit - 2) {
                            emitSecondApos = true;
                            prev = PrevState.OTHER;
                        } else {
                            prev = PrevState.DEFERRED_APOSTROPHE;
                        }
                    } else {
                        // Defer whether second apostrophe is emitted
                        // or not after checking next part.
                        prev = PrevState.DEFERRED_APOSTROPHE;
                    }

                    if (!emitSecondApos) {
                        endIdx = part.getIndex();
                    }
                } else {
                    prev = PrevState.OTHER;
                    if (curApos) {
                        // Single apostrophe designates either start or end of
                        // quoted segment.
                        inQuote = !inQuote;
                    }
                }
            } else if (type == Type.ARG_LIMIT) {
                prev = PrevState.ARG_LIMIT;
            } else {
                prev = PrevState.OTHER;
            }

            buf.append(inputStr.substring(start, endIdx));
            start = limit;
        }

        // Append remaining text
        if (start < inputStr.length()) {
            buf.append(inputStr.substring(start, inputStr.length()));
        }

        return buf.toString();
    }

    public  JavaPropertiesResource(Encoding enc, MessagePatternEscape msgPatEsc);
    public  JavaPropertiesResource();

}