/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import _ from 'lodash';

import { Bean } from './Beans';

import AbstractTransformer from './AbstractTransformer';
import StringBuilder from './StringBuilder';
import VersionService from 'app/services/Version.service';

const versionService = new VersionService();

export default class IgniteSpringTransformer extends AbstractTransformer {
    static escapeXml(str = '') {
        return str.replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&apos;')
            .replace(/>/g, '&gt;')
            .replace(/</g, '&lt;');
    }

    static commentBlock(sb, ...lines) {
        if (lines.length > 1) {
            sb.append('<!--');

            _.forEach(lines, (line) => sb.append(`  ${line}`));

            sb.append('-->');
        }
        else
            sb.append(`<!-- ${_.head(lines)} -->`);
    }

    static appendBean(sb, bean, appendId) {
        const beanTags = [];

        if (appendId)
            beanTags.push(`id="${bean.id}"`);

        beanTags.push(`class="${bean.clsName}"`);

        if (bean.factoryMtd)
            beanTags.push(`factory-method="${bean.factoryMtd}"`);

        sb.startBlock(`<bean ${beanTags.join(' ')}>`);

        _.forEach(bean.arguments, (arg) => {
            if (arg.clsName === 'MAP') {
                sb.startBlock('<constructor-arg>');
                this._constructMap(sb, arg);
                sb.endBlock('</constructor-arg>');
            }
            else if (_.isNil(arg.value)) {
                sb.startBlock('<constructor-arg>');
                sb.append('<null/>');
                sb.endBlock('</constructor-arg>');
            }
            else if (arg.constant) {
                sb.startBlock('<constructor-arg>');
                sb.append(`<util:constant static-field="${arg.clsName}.${arg.value}"/>`);
                sb.endBlock('</constructor-arg>');
            }
            else if (arg.clsName === 'BEAN') {
                sb.startBlock('<constructor-arg>');
                this.appendBean(sb, arg.value);
                sb.endBlock('</constructor-arg>');
            }
            else
                sb.append(`<constructor-arg value="${this._toObject(arg.clsName, arg.value)}"/>`);
        });

        this._setProperties(sb, bean);

        sb.endBlock('</bean>');
    }

    static _toObject(clsName, items) {
        return _.map(_.isArray(items) ? items : [items], (item) => {
            switch (clsName) {
                case 'PROPERTY':
                case 'PROPERTY_CHAR':
                case 'PROPERTY_INT':
                    return `\${${item}}`;
                case 'java.lang.Class':
                    return this.javaTypes.fullClassName(item);
                case 'long':
                    return `${item}`;
                case 'java.lang.String':
                case 'PATH':
                case 'PATH_ARRAY':
                    return this.escapeXml(item);
                default:
                    return item;
            }
        });
    }

    static _isBean(clsName) {
        return this.javaTypes.nonBuiltInClass(clsName) && this.javaTypesNonEnum.nonEnum(clsName) && _.includes(clsName, '.');
    }

    static _setCollection(sb, prop) {
        sb.startBlock(`<property name="${prop.name}">`);
        sb.startBlock('<list>');

        _.forEach(prop.items, (item, idx) => {
            if (this._isBean(prop.typeClsName)) {
                if (idx !== 0)
                    sb.emptyLine();

                this.appendBean(sb, item);
            }
            else
                sb.append(`<value>${item}</value>`);
        });

        sb.endBlock('</list>');
        sb.endBlock('</property>');
    }

    static _constructMap(sb, map) {
        sb.startBlock('<map>');

        _.forEach(map.entries, (entry) => {
            const key = entry[map.keyField];
            const val = entry[map.valField];

            const isKeyBean = key instanceof Bean || this._isBean(map.keyClsName);
            const isValBean = val instanceof Bean || this._isBean(map.valClsName);


            if (isKeyBean || isValBean) {
                sb.startBlock('<entry>');

                sb.startBlock('<key>');
                if (isKeyBean)
                    this.appendBean(sb, key);
                else
                    sb.append(this._toObject(map.keyClsName, key));
                sb.endBlock('</key>');

                sb.startBlock('<value>');
                if (isValBean)
                    this.appendBean(sb, val);
                else
                    sb.append(this._toObject(map.valClsName, val));
                sb.endBlock('</value>');

                sb.endBlock('</entry>');
            }
            else
                sb.append(`<entry key="${this._toObject(map.keyClsName, key)}" value="${this._toObject(map.valClsName, val)}"/>`);
        });

        sb.endBlock('</map>');
    }

    /**
     *
     * @param {StringBuilder} sb
     * @param {Bean} bean
     * @returns {StringBuilder}
     */
    static _setProperties(sb, bean) {
        _.forEach(bean.properties, (prop, idx) => {
            switch (prop.clsName) {
                case 'DATA_SOURCE':
                    const valAttr = prop.name === 'dataSource' ? 'ref' : 'value';

                    sb.append(`<property name="${prop.name}" ${valAttr}="${prop.id}"/>`);

                    break;
                case 'EVENT_TYPES':
                    sb.startBlock(`<property name="${prop.name}">`);

                    if (prop.eventTypes.length === 1) {
                        const evtGrp = _.head(prop.eventTypes);

                        sb.append(`<util:constant static-field="${evtGrp.class}.${evtGrp.label}"/>`);
                    }
                    else {
                        sb.startBlock('<list>');

                        _.forEach(prop.eventTypes, (evtGrp, ix) => {
                            ix > 0 && sb.emptyLine();

                            sb.append(`<!-- EventType.${evtGrp.label} -->`);

                            _.forEach(evtGrp.events, (event) =>
                                sb.append(`<util:constant static-field="${evtGrp.class}.${event}"/>`));
                        });

                        sb.endBlock('</list>');
                    }

                    sb.endBlock('</property>');

                    break;
                case 'ARRAY':
                case 'PATH_ARRAY':
                case 'COLLECTION':
                    this._setCollection(sb, prop);

                    break;
                case 'MAP':
                    sb.startBlock(`<property name="${prop.name}">`);

                    this._constructMap(sb, prop);

                    sb.endBlock('</property>');

                    break;
                case 'java.util.Properties':
                    sb.startBlock(`<property name="${prop.name}">`);
                    sb.startBlock('<props>');

                    _.forEach(prop.entries, (entry) => {
                        sb.append(`<prop key="${entry.name}">${entry.value}</prop>`);
                    });

                    sb.endBlock('</props>');
                    sb.endBlock('</property>');

                    break;
                case 'BEAN':
                    sb.startBlock(`<property name="${prop.name}">`);

                    this.appendBean(sb, prop.value);

                    sb.endBlock('</property>');

                    break;
                default:
                    sb.append(`<property name="${prop.name}" value="${this._toObject(prop.clsName, prop.value)}"/>`);
            }

            this._emptyLineIfNeeded(sb, bean.properties, idx);
        });

        return sb;
    }

    /**
     * Build final XML.
     *
     * @param {Bean} cfg Ignite configuration.
     * @param {Object} targetVer Version of Ignite for generated project.
     * @param {Boolean} clientNearCaches
     * @returns {StringBuilder}
     */
    static igniteConfiguration(cfg, targetVer, clientNearCaches) {
        const available = versionService.since.bind(versionService, targetVer.ignite);

        const sb = new StringBuilder();

        // 0. Add header.
        sb.append('<?xml version="1.0" encoding="UTF-8"?>');
        sb.emptyLine();

        this.mainComment(sb);
        sb.emptyLine();

        // 1. Start beans section.
        sb.startBlock([
            '<beans xmlns="http://www.springframework.org/schema/beans"',
            '       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"',
            '       xmlns:util="http://www.springframework.org/schema/util"',
            '       xsi:schemaLocation="http://www.springframework.org/schema/beans',
            '                           http://www.springframework.org/schema/beans/spring-beans.xsd',
            '                           http://www.springframework.org/schema/util',
            '                           http://www.springframework.org/schema/util/spring-util.xsd">']);

        // 2. Add external property file
        if (this.hasProperties(cfg)) {
            this.commentBlock(sb, 'Load external properties file.');

            sb.startBlock('<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">');
            sb.append('<property name="location" value="classpath:secret.properties"/>');
            sb.endBlock('</bean>');

            sb.emptyLine();
        }

        // 3. Add data sources.
        const dataSources = this.collectDataSources(cfg);

        if (dataSources.length) {
            this.commentBlock(sb, 'Data source beans will be initialized from external properties file.');

            _.forEach(dataSources, (ds) => {
                this.appendBean(sb, ds, true);

                sb.emptyLine();
            });
        }

        _.forEach(clientNearCaches, (cache) => {
            this.commentBlock(sb, `Configuration of near cache for cache "${cache.name}"`);

            this.appendBean(sb, this.generator.cacheNearClient(cache, available), true);

            sb.emptyLine();
        });

        // 3. Add main content.
        this.appendBean(sb, cfg);

        // 4. Close beans section.
        sb.endBlock('</beans>');

        return sb;
    }

    static cluster(cluster, targetVer, client) {
        const cfg = this.generator.igniteConfiguration(cluster, targetVer, client);

        const clientNearCaches = client ? _.filter(cluster.caches, (cache) =>
            cache.cacheMode === 'PARTITIONED' && _.get(cache, 'clientNearConfiguration.enabled')) : [];

        return this.igniteConfiguration(cfg, targetVer, clientNearCaches);
    }
}
