package com.brilliance.mda.runtime.mda.util;

import com.brilliance.mda.runtime.mda.*;
import com.brilliance.mda.runtime.mda.driver.I18NImpl;
import com.brilliance.mda.runtime.mda.driver.MdaDriver;
import com.brilliance.mda.runtime.mda.driver.MdaEnv;
import com.brilliance.mda.runtime.mda.impl.Argument;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import oracle.sql.TIMESTAMP;
import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.Format;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Semaphore;

public class MdaUtils {

    private static final Logger log = LoggerFactory.getLogger(MdaUtils.class);

    static final Format format = new DecimalFormat("#.######");
    static final Format dateFormat = new SimpleDateFormat("yyyy/MM/dd");
    static final Format timeFormat = new SimpleDateFormat("HH:mm");
    public static boolean autoConvert = false;


    static final Map<String, Semaphore> mutexMap = new HashMap();

    static final HashMap<String, Properties> pMap = new HashMap();

    public static synchronized void close() {
        pMap.clear();
    }

    private static synchronized Properties getProperties(String name)
            throws FileNotFoundException, IOException {
        Properties properties = (Properties) pMap.get(name);
        if (properties == null) {
            properties = new Properties();
            properties.load(new FileInputStream(new File(name)));
            pMap.put(name, properties);
        }
        return properties;
    }

    public static String getPropertyValue(String fileName, String key) {
        try {
            return getProperties(fileName).getProperty(key);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    public static void setPropertyValue(String fileName, String key, String value) {
        try {
            Properties properties = getProperties(fileName);
            properties.setProperty(key, value);
            properties.store(new FileOutputStream(mkdirs(fileName)), null);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    private static File mkdirs(String fileName) {
        File file = new File(fileName);
        if (!file.getParentFile().exists())
            file.getParentFile().mkdirs();
        return file;
    }

    public static boolean fileCopy(String sourceFileName, String targetFileName) {
        try {
            File sourceFile = new File(sourceFileName);
            File targetFile = new File(targetFileName);
            if (targetFile.exists()) {
                if (sourceFile.isDirectory())
                    FileUtils.copyDirectoryToDirectory(sourceFile, targetFile);
                else if (targetFile.isDirectory())
                    FileUtils.copyFileToDirectory(sourceFile, targetFile);
                else {
                    FileUtils.copyFile(sourceFile, targetFile);
                }

            } else if (sourceFile.isDirectory()) {
                targetFile.mkdirs();
                FileUtils.copyDirectory(sourceFile, targetFile);
            } else {
                FileUtils.copyFile(new File(sourceFileName), mkdirs(targetFileName));
            }
            return true;
        } catch (Exception e) {
            log.error("fileCopy error", e);
        }
        return false;
    }

    public static boolean fileDelete(String fileName) {
        try {
            FileUtils.forceDelete(new File(fileName));
            return true;
        } catch (Exception e) {
            log.error("fileDelete error", e);
        }
        return false;
    }

    public static boolean fileMove(String sourcefileNameOrPath, String targetFileOrPathName) {
        try {
            File sourceFile = new File(sourcefileNameOrPath);
            File targetFile = new File(targetFileOrPathName);
            if (targetFile.exists()) {
                if (sourceFile.isDirectory())
                    FileUtils.moveDirectoryToDirectory(sourceFile, targetFile, false);
                else if (targetFile.isDirectory())
                    FileUtils.moveFileToDirectory(sourceFile, targetFile, false);
                else {
                    FileUtils.moveFile(sourceFile, targetFile);
                }

            } else if (sourceFile.isDirectory())
                FileUtils.moveDirectoryToDirectory(sourceFile, targetFile, true);
            else {
                FileUtils.moveFile(sourceFile, targetFile);
            }
            return true;
        } catch (Exception e) {
            log.error("fileMove error", e);
        }
        return false;
    }

    public static boolean fileMkdirs(String filePath) {
        return new File(filePath).mkdirs();
    }

    public static String fileName(String fileName) {
        return FilenameUtils.getName(fileName);
    }

    public static String fileBaseName(String fileName) {
        return FilenameUtils.getBaseName(fileName);
    }

    public static String fileExtension(String fileName) {
        return FilenameUtils.getExtension(fileName);
    }

    public static boolean fileExists(String fileName) {
        return new File(fileName).exists();
    }

    public static long fileSize(String fileName) {
        return new File(fileName).length();
    }

    public static Date fileDate(String fileName) {
        return new Date(new File(fileName).lastModified());
    }

    public static String fileMD5Value(String fileName) {
        try {
            return DigestUtils.md5Hex(new FileInputStream(fileName));
        } catch (Exception e) {
            log.error("Get MD5 error.", e);
        }
        return null;
    }

    public static void fileArchive(String zipFileName, String[] fileNames, String baseDirectoryName) {
        try {
            ArchiveUtils.archive(new FileOutputStream(zipFileName), fileNames, baseDirectoryName);
        } catch (Exception e) {
            log.error("Archive file error.", e);
        }
    }

    public static void fileArchive(IStream zipStream, String[] fileNames, String baseDirectoryName) {
        try {
            ArchiveUtils.archive(zipStream.getOutputStream(), fileNames, baseDirectoryName);
        } catch (Exception e) {
            log.error("Archive file error.", e);
        }
    }

    public static boolean fileExtract(String zipFileName, String entryName, String outputFileName) {
        try {
            return ArchiveUtils.extract(new FileInputStream(zipFileName), entryName, new FileOutputStream(outputFileName));
        } catch (Exception e) {
            log.error("Extract file error.", e);
        }
        return false;
    }

    public static boolean fileExtract(IStream zipStream, String entryName, IStream outputStream) {
        try {
            return ArchiveUtils.extract(zipStream.getInputStream(), entryName, outputStream.getOutputStream());
        } catch (Exception e) {
            log.error("Extract file error.", e);
        }
        return false;
    }

    public static void streamSave(IStream stream, String fileName) {
        try {
            File file = mkdirs(fileName);
            copy(stream.getInputStream(), new FileOutputStream(file));
            stream.close();
//            if (clusterUsed)
//                clusterSendFile(file);
        } catch (Exception e) {
            log.error("streamSave error.", e);
        }
    }

    public static void streamLoad(IStream stream, String fileName) {
        try {
            stream.close();

            copy(new FileInputStream(new File(fileName)), stream.getOutputStream());
        } catch (Exception e) {
            log.error("streamLoad error.", e);
        }
    }

    public static void streamClear(IStream stream) {
        stream.close();
    }

    public static final void copy(InputStream is, OutputStream os)
            throws IOException {
        try {
            IOUtils.copy(is, os);
        } finally {
            closeQuietly(is);
            closeQuietly(os);
        }
    }

    public static final void copy(Reader reader, OutputStream os, Charset charset)
            throws IOException {
        try {
            IOUtils.copy(reader, os, charset);
        } finally {
            closeQuietly(reader);
            closeQuietly(os);
        }
    }

    public static final void closeQuietly(Closeable closeable) {
        try {
            if (closeable != null)
                closeable.close();
        } catch (Exception localException) {
        }
    }

    public static final String decode(byte[] data, DecodeType type) {
        switch (type) {
            case DECODE_MD5:
                return DigestUtils.md5Hex(data);
            case DECODE_SHA:
                return DigestUtils.sha1Hex(data);
            case DECODE_SHA256:
                return DigestUtils.sha256Hex(data);
            case DECODE_SHA384:
                return DigestUtils.sha384Hex(data);
            case DECODE_SHA512:
                return DigestUtils.sha512Hex(data);
            case DECODE_BASE64:
                return Base64.encodeBase64String(data);
        }
        return new String(data);
    }

    public static final String toString(Object object) {
        if ((object == null) || ((object instanceof String)))
            return (String) object;
        try {
            if ((object instanceof IStream))
                return IOUtils.toString(((IStream) object).getInputStream(), Charset.defaultCharset());
            if ((object instanceof IDatafield))
                return toString(((IDatafield) object).getValue());
            return object.toString();
        } catch (Exception e) {
        }
        return null;
    }

    public static final int parseInt(Object value) {
        if (value == null)
            return 0;
        try {
            if ((value instanceof IDatafield))
                return parseInt(((IDatafield) value).getValue());
            if ((value instanceof String))
                return Integer.parseInt((String) value);
            return Integer.parseInt(value.toString());
        } catch (Exception e) {
        }
        return 0;
    }

    public static final BigDecimal parseDecimal(Object value) {
        if (value == null)
            return BigDecimal.ZERO;
        try {
            if ((value instanceof IDatafield))
                return parseDecimal(((IDatafield) value).getValue());
            if ((value instanceof String))
                return new BigDecimal((String) value);
            return new BigDecimal(value.toString());
        } catch (Exception e) {
        }
        return BigDecimal.ZERO;
    }

    public static final Boolean parseBoolean(Object value, Boolean defaultValue) {
        if (value == null)
            return defaultValue;
        try {
            if ((value instanceof IDatafield))
                return parseBoolean(((IDatafield) value).getValue(), defaultValue);
            if ((value instanceof Boolean))
                return (Boolean) value;
            return Boolean.valueOf(Boolean.parseBoolean(value.toString()));
        } catch (Exception e) {
        }
        return defaultValue;
    }

    public static final Date parseDate(Object value, String pattern) {
        if (value == null)
            return null;
        try {
            if ((value instanceof IDatafield))
                return parseDate(((IDatafield) value).getValue(), pattern);
            String v = (value instanceof String) ? (String) value : value.toString();
            SimpleDateFormat format = new SimpleDateFormat(pattern);
            return format.parse(v);
        } catch (Exception e) {
        }
        return null;
    }

    public static final String getI18nStr(String name, String key) {
        return "/" + name + "/" + key + "/";
    }

    public static void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (Exception localException) {
        }
    }

    public static int diff(Date date1, Date date2) {
        return date1.compareTo(date2);
    }

    public static Date add(Date date, int days) {
        return add(date, 5, days);
    }

    public static Date add(Date date, int type, int value) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(type, value);
        return c.getTime();
    }

    public static Date today() {
        return new Date();
    }

    public static String format(Object object, String pattern) {
        if (object == null)
            return null;
        if ((object instanceof IDatafield))
            return format(((IDatafield) object).getValue(), pattern);
        if (pattern.startsWith("%"))
            return String.format(pattern, new Object[]{object});
        if ((object instanceof Number))
            return new DecimalFormat(pattern).format(object);
        if ((object instanceof Date))
            return new SimpleDateFormat(pattern).format(object);
        return new MessageFormat(pattern).format(object);
    }

    public static boolean isEmpty(Object object) {
        if (object == null)
            return true;
        if ((object instanceof String))
            return "".equals(((String) object).trim());
        if ((object instanceof StringBuffer))
            return isEmpty(((StringBuffer) object).toString());
//        if ((object instanceof IModule))
//            return ((IModule)object).isEmpty();
        if ((object instanceof IStream))
            return ((IStream) object).isEmpty();
        if ((object instanceof IDatafield))
            return isEmpty(((IDatafield) object).getValue());
        if ((object instanceof Number))
            return ((Number) object).doubleValue() == 0.0D;
        if ((object instanceof Collection))
            return ((Collection) object).isEmpty();
        if ((object instanceof Map))
            return ((Map) object).isEmpty();
        if ((object instanceof Argument))
            return isEmpty(((Argument) object).getValue());
        return false;
    }

    public static boolean exists(Object object, String methodName, Object... args) {
        return exists(object, methodName, null, args);
    }

    public static boolean exists(Object object, String methodName, Class[] classes, Object[] args) {
        if (classes == null) {
            classes = new Class[args.length];
            for (int i = 0; i < args.length; i++)
                classes[i] = args[i].getClass();
        }
        try {
            if ((object instanceof String))
                return MethodUtils.getAccessibleMethod(Class.forName((String) object), methodName, classes) != null;
            return MethodUtils.getAccessibleMethod(object.getClass(), methodName, classes) != null;
        } catch (Exception e) {
        }
        return false;
    }

    public static Object invoke(Object object, String methodName, Object... args) {
        return invoke(object, methodName, null, args);
    }

    public static Object invoke(Object object, String methodName, Class[] classes, Object[] args) {
        try {
            if (classes == null) {
                classes = new Class[args.length];
                for (int i = 0; i < args.length; i++)
                    classes[i] = args[i].getClass();
            }
            if ((object instanceof String))
                return MethodUtils.invokeStaticMethod(Class.forName((String) object), methodName, args, classes);
            return MethodUtils.invokeMethod(object, methodName, args, classes);
        } catch (Exception e) {
            log.info("invoke errr.", e);
        }
        return null;
    }

    public static Object getProperty(Object object, String propertyName) {
        try {
            return PropertyUtils.getProperty(object, propertyName);
        } catch (Exception e) {
            log.info("getProperty", e);
        }
        return null;
    }

    public static void setProperty(Object object, String propertyName, Object value) {
        try {
//            if ((object instanceof IModule))
//                ((IDatafield)((IModule)object).get(propertyName)).setValue(value);
//            else
            PropertyUtils.setProperty(object, propertyName, value);
        } catch (Exception e) {
            log.info("setProperty", e);
        }
    }

    public static String catPath(String path, String subPath) {
        return new File(new File(path), subPath).getAbsolutePath();
    }

    public static List<String> listFiles(String path, String[] extensions) {
        List list = new ArrayList();
        try {
            for (File file : FileUtils.listFiles(new File(path), extensions, false))
                list.add(file.getAbsolutePath());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return list;
    }

    public static List<String> listDirectories(String path) {
        List list = new ArrayList();
        try {
            for (File file : new File(path).listFiles((FileFilter) DirectoryFileFilter.DIRECTORY))
                list.add(file.getAbsolutePath());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return list;
    }

    public static boolean clear(Object object) {
        if (object == null)
            return true;
        if ((object instanceof IBaseObject))
            ((IBaseObject) object).clear();
        else if ((object instanceof Collection))
            ((Collection) object).clear();
        else if ((object instanceof Map))
            ((Map) object).clear();
        else if ((object instanceof IStream))
            ((IStream) object).close();
        else if ((object instanceof IDatafield)) {
            if (!clear(((IDatafield) object).getValue()))
                ((IDatafield) object).setValue(null);
        } else if ((object instanceof IModule)) {
            if (!clear(((IDatafield) object).getValue()))
                MdaDriver.clearModule((IModule) object);
        } else
            return false;
        return true;
    }

    public static Date sqlDate(Date date, OpType type) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        switch (type) {
            case DESC:
            case GE:
                c.set(11, 23);
                c.set(12, 59);
                c.set(13, 59);
                c.set(14, 999);
                if (type == OpType.LT)
                    return new Timestamp(c.getTime().getTime());
                return new Date(c.getTime().getTime());
            case BETWEEN:
            case EQ:
                c.set(11, 0);
                c.set(12, 0);
                c.set(13, 0);
                c.set(14, 0);
                if (type == OpType.GT)
                    return new Timestamp(c.getTime().getTime());
                return new Date(c.getTime().getTime());
        }
        return date;
    }

    public static final List<String> loadLines(String fileName, String encoding) {
        try {
            FileInputStream fis = new FileInputStream(fileName);
            List list = IOUtils.readLines(fis, encoding);
            fis.close();
            return list;
        } catch (Exception e) {
            log.error("Read lines error.", e);
        }
        return Collections.EMPTY_LIST;
    }

    public static final void saveLines(List<String> lines, String lineEnding, String fileName, String encoding) {
        try {
            IOUtils.writeLines(lines, "", new FileOutputStream(fileName), encoding);
        } catch (Exception e) {
            log.error("Save lines error.", e);
        }
    }

    public static final String loadContent(String fileName, String encoding) {
        try {
            FileInputStream fis = new FileInputStream(fileName);
            String content = IOUtils.toString(fis, encoding);
            fis.close();
            return content;
        } catch (Exception e) {
            log.error("Load content error.", e);
        }
        return null;
    }

    public static final void saveContent(String content, String fileName, String encoding) {
        try {
            IOUtils.write(content, new FileOutputStream(fileName), encoding);
        } catch (Exception e) {
            log.error("Load content error.", e);
        }
    }

    private static final void resetQuietly(IStream s) {
        try {
            s.getInputStream().reset();
        } catch (IOException localIOException) {
        }
    }

    private static final Workbook getWorkbook(IStream s) {
        Workbook wb = null;
        try {
            wb = new HSSFWorkbook(s.getInputStream());
        } catch (OfficeXmlFileException _) {
            try {
                resetQuietly(s);
                wb = new XSSFWorkbook(s.getInputStream());
            } catch (IOException e) {
                log.warn("load excel error.", e);
            }
        } catch (IOException e) {
            log.warn("load excel error.", e);
        }
        resetQuietly(s);
        return wb;
    }

    public static final String[] loadExcelSheetNames(IStream s) {
        Workbook wb = getWorkbook(s);
        if (wb == null)
            return null;
        int count = wb.getNumberOfSheets();
        String[] sheetNames = new String[count];
        for (int i = 0; i < count; i++)
            sheetNames[i] = wb.getSheetName(i);
        resetQuietly(s);
        return sheetNames;
    }

    public static final int loadExcel(List<String[]> list, IStream s, int sheetIndex, int rowOffset, int rowMax, int columnOffset, int columnCount) {
        Workbook wb = getWorkbook(s);
        if (wb == null)
            return -1;
        if ((sheetIndex < 0) || (sheetIndex >= wb.getNumberOfSheets())) {
            log.warn("load excel sheet with a illegal index.");
            return -3;
        }
        Sheet sheet = wb == null ? null : wb.getSheetAt(sheetIndex);
        if (sheet == null) {
            log.warn("load excel sheet error.");
            return -2;
        }

        int rows = rowMax > 0 ? Math.min(rowMax, sheet.getLastRowNum() - rowOffset) : sheet.getLastRowNum() - rowOffset;
        if (columnCount > 0) {
            for (int i = 0; i <= rows; i++) {
                Row row = sheet.getRow(i + rowOffset);
                String[] values = new String[columnCount];
                for (int j = 0; j < columnCount; j++) {
                    if (row == null) {
                        values[j] = "";
                    } else {
                        Cell cell = row.getCell(j + columnOffset);
                        values[j] = (cell != null ? getCellValue(cell, cell.getCellTypeEnum()) : "");
                    }
                }
                list.add(values);
            }
        }
        return rows;
    }

    private static final String getCellValue(Cell cell, CellType type) {
        switch (type) {
            case FORMULA:
                return getCellValue(cell, cell.getCachedFormulaResultTypeEnum());
            case ERROR:
                return cell.getStringCellValue();
            case BOOLEAN:
                int df = cell.getCellStyle().getDataFormat();

                if ((df == 20) || (df == 32))
                    return timeFormat.format(cell.getDateCellValue());
                if ((DateUtil.isInternalDateFormat(df)) || (df == 31) || (df == 57) || (df == 58) || (DateUtil.isCellDateFormatted(cell)))
                    return dateFormat.format(cell.getDateCellValue());
                return format.format(Double.valueOf(cell.getNumericCellValue()));
        }
        return cell.toString();
    }

    private static final int unloadExcel(Object value, Row row, int cellNum) {
        Cell cell = row.createCell(cellNum);
        if ((value != null) && ((value instanceof Number))) {
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue(((Number) value).doubleValue());
        } else {
            cell.setCellType(CellType.STRING);
            if ((value == null) || ((value instanceof String)))
                cell.setCellValue((String) value);
            else
                cell.setCellValue(value.toString());
        }
        return cellNum + 1;
    }

    private static final void unloadExcel(List list, Sheet sheet) {
        int rowNum = 0;
        for (Iterator localIterator1 = list.iterator(); localIterator1.hasNext(); ) {
            Object values = localIterator1.next();

            Row row = sheet.createRow(rowNum);
            int cellNum = 0;
            if ((values instanceof Iterable)) {
                for (Iterator localIterator2 = ((Iterable) values).iterator(); localIterator2.hasNext(); ) {
                    Object value = localIterator2.next();
                    cellNum = unloadExcel(value, row, cellNum);
                }
            } else if ((values instanceof Object[])) {
                for (Object value : (Object[]) values)
                    cellNum = unloadExcel(value, row, cellNum);
            }
            rowNum++;
        }
    }

    public static final void unloadExcel(List[] lists, String[] sheetNames, IStream s, boolean flag) {
        Workbook wb = flag ? new XSSFWorkbook() : new HSSFWorkbook();
        OutputStream os = null;
        try {
            for (int i = 0; i < lists.length; i++) {
                List list = lists[i];
                String sheetname = sheetNames[i];
                Sheet sheet = isEmpty(sheetname) ? wb.createSheet() : wb.createSheet(sheetname);
                unloadExcel(list, sheet);
            }
            os = s.getOutputStream();
            wb.write(os);
            os.flush();
        } catch (IOException e) {
            log.error("unload Excel error.", e);
        } finally {
            closeQuietly(os);
            closeQuietly(wb);
        }
    }

    public static final void unloadExcel(List list, IStream s, boolean flag) {
        unloadExcel(new List[]{list}, new String[1], s, flag);
    }

    public static final void generate(String templateFileName, String fileName, String exportType, Map params, Object data) {
//        FileOutputStream fos = null;
//        try {
//            fos = new FileOutputStream(fileName);
//            ReportUtils.generate(templateFileName, fos, exportType, params, data);
//        } catch (Exception e) {
//            log.error("Generate report error.", e);
//        } finally {
//            closeQuietly(fos);
//        }
    }

    public static final void generate(String templateFileName, IStream is, String exportType, Map params, Object data) {
//        try {
//            ReportUtils.generate(templateFileName, is.getOutputStream(), exportType, params, data);
//        } catch (Exception e) {
//            log.error("Generate report error.", e);
//        }
    }


    public static final synchronized void createMutex(String name, int size) {
        Semaphore semaphore = (Semaphore) mutexMap.get(name);
        if (semaphore == null) {
            semaphore = new Semaphore(size);
            mutexMap.put(name, semaphore);
        }
    }

    public static final void releaseMutex(String name) {
        Semaphore semaphore = (Semaphore) mutexMap.get(name);
        if (semaphore != null)
            semaphore.release();
    }

    public static final void acquireMutex(String name) {
        Semaphore semaphore = (Semaphore) mutexMap.get(name);
        if (semaphore != null) {
            try {
                semaphore.acquire();
            } catch (Exception e) {
                log.info("acquireMutex '" + name + "' error.", e);
            }
        }
    }

    public static final void forceDelete(File path)
            throws IOException {
        IOException exception = null;
        for (int i = 0; i < 10; ) {
            try {
                FileUtils.forceDelete(path);
                return;
            } catch (IOException e) {
                exception = e;
                try {
                    Thread.sleep(1000L);
                } catch (Exception localException) {
                }
                i++;
            }

        }

        throw exception;
    }

    public static final int getFormatLength(String format, int length) {
        int index = format.indexOf('.');
        String str = "";
        if (index < 0) {
            for (int i = 0; i < length; i++)
                str = str + "1";
        } else {
            int bits = format.length() - index;
            for (int i = 0; i < length - bits + 1; i++)
                str = str + "1";
            str = str + ("".equals(str) ? "0." : ".");
            for (int i = 0; i < bits; i++)
                str = str + "1";
        }
        str = new DecimalFormat(format).format(new BigDecimal(str));
        return str.length();
    }

    public static final String combineStyle(String oldStyle, String style) {
        if (isEmpty(oldStyle))
            return style;
        if (isEmpty(style))
            return oldStyle;
        return combineStyle(new StringBuffer(oldStyle), style).toString();
    }

    public static final StringBuffer combineStyle(StringBuffer oldStyle, String style) {
        if (isEmpty(oldStyle))
            return oldStyle.append(style);
        if (isEmpty(style)) {
            return oldStyle;
        }
        oldStyle.insert(0, style + ";");
        String[] attributes = oldStyle.toString().split("\\;");
        oldStyle = new StringBuffer();
        List list = new ArrayList();
        for (String attribute : attributes) {
            String[] pairs = attribute.split("\\:");
            if (pairs.length != 2)
                continue;
            String name = pairs[0].trim();
            if (list.contains(name))
                continue;
            list.add(name);
            oldStyle.append(name).append(":").append(pairs[1]).append(";");
        }

        return oldStyle;
    }

    public static final String getWebType(IStream stream) {
        String type = stream.getType();
        return isEmpty(type) ? "pdf" : type;
    }

    public static final String getWebFileName(String browserType, IStream stream) {
        try {
            String name = stream.getName();
            if (isEmpty(name))
                name = "default." + getWebType(stream);
            if (!autoConvert)
                return name;
            log.debug("Type of browser is:\t" + browserType);
            if ((isEmpty(browserType)) || (browserType.contains("MSIE")))
                return URLEncoder.encode(name, "UTF-8");
            return new String(name.getBytes(), "ISO8859-1");
        } catch (Exception e) {
        }
        return "default." + getWebType(stream);
    }

    public static boolean equals(String value1, String value2) {
        if (value1 == null)
            return value2 == null;
        return value1.equals(value2);
    }

    public static void exitRule() {
        throw new RuleExitException("终止当前Rule");
    }

    public static List<CodetableItem> getCodetable(String codeName) {
        return null;
    }

    public static String encryptPassword(String srcPassword) {
        return new String(DigestUtils.sha1(DigestUtils.md5(srcPassword)));
    }

    public static void saveData(IModule module, IStream os) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            mapper.writeValue(os.getOutputStream(), module);
        } catch (Exception e) {
            log.error("模型序列化异常", e);
        }
    }

    public static String getCodetableLabel(String codetable, String toString) {
        return null;
    }

    public static String getPath(IBaseObject baseObject) {
        return baseObject.getPath();
    }

    public static void loadData(IModule module, IStream stream) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            module.copyValues(mapper.readValue(stream.getInputStream(), module.getClass()));
        } catch (Exception e) {
            log.error("模型反序列化异常", e);
        }
    }

    public static String toJson(Object dataMap) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writeValueAsString(dataMap);
        } catch (Exception e) {
            log.error("转换JSON异常", e);
        }
        return "";
    }

    public static <T> T fromJson(String json, Class<T> clazz) {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.convertValue(json, clazz);
    }

    public static String covCnAmt(BigDecimal amt) {
        try {
            if (amt == null)
                return "";
            String strAmt = amt.setScale(2, 4).toString();
            String[] number = {"壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
            String[] radices = {"仟", "", "拾", "佰"};
            String[] bigRadices = {"", "万", "亿", "万亿", "亿亿"};
            int idx = strAmt.indexOf(".");
            String sInt = strAmt.substring(0, idx);
            String sFlt = strAmt.substring(idx + 1);
            String cn = "";
            int zeroC = 0;
            int len = sInt.length();
            for (int i = 0; i < len; i++) {
                if (sInt.charAt(i) == '0') {
                    zeroC++;
                } else {
                    if (zeroC > 0) {
                        cn = String.valueOf(cn) + "零";
                        zeroC = 0;
                    }
                    cn = String.valueOf(cn) + number[sInt.charAt(i) - 49];
                    cn = String.valueOf(cn) + radices[(len - i) % 4];
                }
                if ((len - i) % 4 == 1 && zeroC < 4)
                    cn = String.valueOf(cn) + bigRadices[(len - i) / 4];
            }
            cn = String.valueOf(cn) + "元";
            if (sFlt.equals("00")) {
                cn = String.valueOf(cn) + "整";
            } else {
                if (!sFlt.substring(0, 1).equals("0")) {
                    cn = String.valueOf(cn) + number[sFlt.charAt(0) - 49] + "角";
                } else {
                    cn = String.valueOf(cn) + "零";
                }
                if (!sFlt.substring(1, 2).equals("0"))
                    cn = String.valueOf(cn) + number[sFlt.charAt(1) - 49] + "分";
            }
            log.debug("cn===" + cn);
            return cn;
        } catch (Exception e) {
            log.error("covCnAmt error", e);
            return "";
        }
    }

    static String covEnAmt(BigDecimal amt) {
        if (amt == null)
            return "";
        String strAmt = amt.setScale(2, 4).toString();
        String[] words1 = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
        String[] words4 = {"hundred", "thousand", "million", "billion", "trillion"};
        int idx = strAmt.indexOf(".");
        String sInt = strAmt.substring(0, idx);
        String sFlt = strAmt.substring(idx + 1);
        int lenZ = sInt.length();
        if (lenZ > 15)
            return "";
        String en = "";
        if (lenZ > 12) {
            String str = sInt.substring(0, lenZ - 9);
            if (!"000".equals(str))
                en = String.valueOf(en) + convertdhundred(str) + " " + words4[4] + " ";
            sInt = sInt.substring(lenZ - 9);
            lenZ = sInt.length();
        }
        if (lenZ > 9) {
            String str = sInt.substring(0, lenZ - 9);
            if (!"000".equals(str))
                en = String.valueOf(en) + convertdhundred(str) + " " + words4[3] + " ";
            sInt = sInt.substring(lenZ - 9);
            lenZ = sInt.length();
        }
        if (lenZ > 6) {
            String str = sInt.substring(0, lenZ - 6);
            if (!"000".equals(str))
                en = String.valueOf(en) + convertdhundred(str) + " " + words4[2] + " ";
            sInt = sInt.substring(lenZ - 6);
            lenZ = sInt.length();
        }
        if (lenZ > 3) {
            String str = sInt.substring(0, lenZ - 3);
            if (!"000".equals(str))
                en = String.valueOf(en) + convertdhundred(str) + " " + words4[1] + " ";
            sInt = sInt.substring(lenZ - 3);
            lenZ = sInt.length();
        }
        String s = sInt;
        if (!"000".equals(s))
            en = String.valueOf(en) + convertdhundred(s);
        int lenF = sFlt.length();
        if (lenF > 0) {
            String w2 = " ";
            boolean allZero = true;
            for (int i = 0; i < lenF; i++) {
                int n = sFlt.charAt(i) - 48;
                w2 = String.valueOf(w2) + words1[n] + " ";
                if (n > 0)
                    allZero = false;
            }
            if (!"0".equals(s)) {
                w2 = " and cents " + convertdhundred(sFlt);
            } else {
                w2 = " cents " + convertdhundred(sFlt);
            }
            if (!allZero) {
                en = String.valueOf(en) + w2;
            } else {
                en = String.valueOf(en) + " only ";
            }
        } else {
            en = String.valueOf(en) + " only ";
        }
        return en;
    }

    static String convertdhundred(String s) {
        String[] words1 = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
        String[] words2 = {"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
                "eighteen", "nineteen"};
        String[] words3 = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
        String[] words4 = {"hundred", "thousand", "million", "billion"};
        char c1 = '0';
        char c2 = '0';
        char c3 = '0';
        if (s.length() > 2) {
            c1 = s.charAt(0);
            c2 = s.charAt(1);
            c3 = s.charAt(2);
        } else if (s.length() > 1) {
            c1 = '0';
            c2 = s.charAt(0);
            c3 = s.charAt(1);
        } else if (s.length() > 0) {
            c1 = '0';
            c2 = '0';
            c3 = s.charAt(0);
        }
        int n1 = c1 - 48;
        int n2 = c2 - 48;
        int n3 = c3 - 48;
        String word = "";
        if (n1 > 0)
            word = String.valueOf(word) + words1[n1] + " " + words4[0] + " ";
        if (n1 != 0 && n2 == 0 && n3 != 0)
            word = String.valueOf(word) + " and ";
        if (n2 == 1) {
            word = String.valueOf(word) + words2[n3] + " ";
        } else if (n2 > 1) {
            word = String.valueOf(word) + words3[n2] + " ";
            if (n3 > 0)
                word = String.valueOf(word) + words1[n3];
        } else if (n3 > 0) {
            word = String.valueOf(word) + words1[n3];
        }
        return word.trim();
    }

    private static I18n i18N = new I18NImpl();

    public static String getI18NString(String moduleName, String key) {
        Locale locale = MdaEnv.getLocale();

        String desp = i18N.getString(locale, moduleName, key);
        if (Strings.isEmpty(desp) || desp.startsWith("???")) {
            if (locale == Locale.SIMPLIFIED_CHINESE)
                desp = i18N.getString(Locale.US, moduleName, key);
            else if (locale == Locale.US)
                desp = i18N.getString(Locale.SIMPLIFIED_CHINESE, moduleName, key);
        }
        return desp;
    }


    public static boolean prompt(Object... o) {
        return true;
    }

    public static String generateSerialNum() {
        return UUID.randomUUID().toString();
    }

    public static int compareTo(Object o1, Object o2) {
        if (o1 instanceof Boolean) {
            int var1 = o1.equals(Boolean.TRUE) ? 1 : 0;
            return compareTo(var1, o2);
        }
        if (o2 instanceof Boolean) {
            int var2 = o2.equals(Boolean.TRUE) ? 1 : 0;
            return compareTo(o1, var2);
        }

        //拆箱展开
        if (o1 instanceof Argument) {
            o1 = ((Argument) o1).value;
        }
        //拆箱展开2
        if (o2 instanceof Argument) {
            o2 = ((Argument) o2).value;
        }
        if (o1 == null && o2 == null) return 0;
        if (o1 == null) {
            if ("".equals(o2)) {
                return 0;
            }
            return 1;
        }
        if (o2 == null) {
            if ("".equals(o1)) {
                return 0;
            }
            return -1;
        }
        //先做空判断，使 " " == ""
        if (o1 instanceof String && o2 instanceof String) {
            if (isEmpty(((String) o1).trim()) && isEmpty(((String) o2).trim()))
                return 0;
            return (((String) o1).trim()).compareTo(((String) o2).trim());
        }

        if (o1 instanceof String)
            return (((String) o1).trim()).compareTo((String) o2);
        else if (o1 instanceof Number && o2 instanceof Number) {
            double i1 = ((Number) o1).doubleValue();
            double i2 = ((Number) o2).doubleValue();
            if (i1 > i2)
                return 1;
            else if (i1 == i2)
                return 0;
            else
                return -1;
        } else if (o1 instanceof BigDecimal && o2 instanceof Number) {
            BigDecimal o2decimal = null;
            if (o2 instanceof Double) {
                o2decimal = new BigDecimal(Double.toString((Double) o2));
            } else if (o2 instanceof Long) {
                o2decimal = new BigDecimal(Long.toString((Long) o2));
            } else if (o2 instanceof Float) {
                o2decimal = new BigDecimal(Float.toString((Float) o2));
            } else
                o2decimal = new BigDecimal(o2.toString());

            return ((BigDecimal) o1).compareTo(o2decimal);
        } else if (o1 instanceof Number && o2 instanceof BigDecimal) {
            return -compareTo(o2, o1);
        } else if (o1 instanceof BigDecimal && o2 instanceof BigDecimal) {
            return (((BigDecimal) o1).compareTo((BigDecimal) o2));
        } else if (o1 instanceof TIMESTAMP && o2 instanceof TIMESTAMP) {
            try {
                return compareTo(((TIMESTAMP) o1).timestampValue(), ((TIMESTAMP) o2).timestampValue());
            } catch (Exception throwables) {
                throw new IllegalArgumentException("不支持的比较类型！");
            }
        } else if (o1 instanceof Date)
            return (((Date) o1).compareTo((Date) o2));
        else if (o1 instanceof Byte)
            return (((Byte) o1).compareTo((Byte) o2));
        else if (o1 instanceof Character)
            return (((Character) o1).compareTo((Character) o2));
        else if (o1 instanceof Short)
            return (((Short) o1).compareTo((Short) o2));
        else if (o1 instanceof Long)
            return (((Long) o1).compareTo((Long) o2));
        else if (o1 instanceof Float)
            return (((Float) o1).compareTo((Float) o2));
        else if (o1 instanceof Double)
            return (((Double) o1).compareTo((Double) o2));
        else if (o1 instanceof IStream && o2 instanceof IStream) {
            IStream is1 = (IStream) o1;
            IStream is2 = (IStream) o2;
            if (is1.getRows().size() == 0 && is2.getRows().size() == 0)
                return 0;
            if (is1.getRows().size() > is2.getRows().size())
                return 1;
            else if (is1.getRows().size() < is2.getRows().size())
                return -1;
            else {
                for (int i = 0; i < is1.getRows().size(); i++) {
                    int diff = is1.getRows().get(i).compareTo(is2.getRows().get(i));
                    if (diff != 0)
                        return diff;
                }
                return 0;
            }
        } else {
            throw new IllegalArgumentException("不支持的比较类型！");
        }
    }


    /**
     * @param name
     * @param key
     * @return
     */
    public static String getI18nValue(String name, String key) {
        return getI18NString(name, key);
    }


    /**
     * todo
     *
     * @param path
     * @return
     */
    public static List<String> listFiles(String path) {
        return null;
    }

    /**
     * todo
     *
     * @return
     */
    public static String getDatasourceName() {
        return "";
    }

    /**
     * todo
     *
     * @return
     */
    public static boolean isBackground() {
        IContext ctx = MdaEnv.getContext();
        // ctx.getGui().isBackground()
        return false;
    }


    /**
     * todo
     */
    public static void returnToFirst() {
        IContext ctx = MdaEnv.getContext();
        // ctx.getGui().chain(Constants.FIRST);
    }

    /**
     * todo
     *
     * @return
     */
    public static boolean isReturnCall() {
        IContext ctx = MdaEnv.getContext();
        //ctx.getSession().isReturnCall()
        return false;
    }

    /**
     * todo
     */
    public static Object invokeEx(Object... o) {
        IContext ctx = MdaEnv.getContext();
        // ctx.getSupport().invoke
        return null;
    }

    /**
     * todo
     *
     * @param o
     */
    public static void setValues(Object... o) {

    }

    /**
     * todo
     */
    public static void showMainPanel() {
    }

    /**
     * todo
     */
    public static void resetModified(Object... o) {
    }


}
