/*
 * Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.codegen;

import java.io.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.exceptions.*;

/**
 * INTERNAL:
 * <p><b>Purpose</b>: Used to generate code
 *
 * @since TopLink 3.0
 * @author James Sutherland
 */
public class CodeGenerator {
    protected Writer output;
    protected ClassDefinition currentClass;

    /*Bug#3388703 useUnicode is added to provide user with an option to escape
    non-ASCII characters or not */
    protected boolean useUnicode = true;

    public CodeGenerator() {
        this.output = new StringWriter();
    }

    public CodeGenerator(boolean useUnicode) {
        this();
        this.useUnicode = useUnicode;
    }

    public void cr() {
        write(Helper.cr());
    }

    public ClassDefinition getCurrentClass() {
        return currentClass;
    }

    public Writer getOutput() {
        return output;
    }

    public void setCurrentClass(ClassDefinition currentClass) {
        this.currentClass = currentClass;
    }

    public void setOutput(Writer output) {
        this.output = output;
    }

    public void tab() {
        write("\t");
    }

    public void tab(int indent) {
        for (int index = 0; index < indent; index++) {
            tab();
        }
    }

    public String toString() {
        return getOutput().toString();
    }

    public void write(Object value) {
        try {

            /*Bug#3388703 useUnicode is added to provide user with an option to escape
            non-ASCII characters or not */
            if (!useUnicode) {
                getOutput().write(String.valueOf(value));
            } else {
                //Bug2906180  \\uxxxx escaped characters are used for non-ASCII characters
                String test = String.valueOf(value);
                StringBuilder escapedStr = new StringBuilder(test.length() * 4);
                for (int i = 0; i < test.length(); i++) {
                    char c = test.charAt(i);
                    if (c < 127) {
                        escapedStr.append(c);
                    } else {
                        String escapedChar = Long.toHexString((c)).toUpperCase();
                        switch (escapedChar.length()) {
                        case 1:
                            escapedStr.append("\\u000" + escapedChar);
                            break;
                        case 2:
                            escapedStr.append("\\u00" + escapedChar);
                            break;
                        case 3:
                            escapedStr.append("\\u0" + escapedChar);
                            break;
                        default:
                            escapedStr.append("\\u" + escapedChar);
                            break;
                        }
                    }
                }
                getOutput().write(escapedStr.toString());
            }
        } catch (IOException exception) {
            throw ValidationException.fileError(exception);
        }
    }

    public void writeln(Object value) {
        write(value);
        cr();
    }

    /**
     * Write the type checking if its package is required.
     */
    public void writeType(String typeName) {
        String localTypeName = typeName;
        if (getCurrentClass() != null) {
            int index = typeName.lastIndexOf('.');
            if (index != -1) {
                String packageName = typeName.substring(index);
                if (getCurrentClass().getImports().contains(packageName)) {
                    localTypeName = typeName.substring(index, typeName.length());
                }
            }
        }
        write(localTypeName);
    }
}
