/**
 * $Id$
 * Copyright(C) 2012-2016 configx.com. All rights reserved.
 */
package com.configx.client.env;

import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 多版本的{@link PropertySource}，每个版本保存更新的属性，新版本从旧版本继承属性，新版本覆盖旧版本的属性
 *
 * @author zhirong.zou
 */
public class MultiVersionPropertySource extends EnumerablePropertySource<Object> {

    private final List<VersionPropertySource<?>> propertySources = new CopyOnWriteArrayList<>();

    public MultiVersionPropertySource(String name) {
        super(name);
    }

    /**
     * 返回指定版本的属性源
     *
     * @param version
     * @return
     */
    public VersionPropertySource<?> getPropertySource(long version) {
        for (VersionPropertySource<?> propertySource : this.propertySources) {
            if (propertySource.getVersion() == version) {
                return propertySource;
            }
        }
        return null;
    }

    @Override
    public Object getProperty(String name) {
        return ConfigVersionManager.doWithVersion(version -> {
            VersionPropertySource<?> propertySource = null;
            for (int index = this.propertySources.size() - 1; index >= 0; index--) {
                propertySource = this.propertySources.get(index);

                if (propertySource.getVersion() <= version) {
                    Object candidate = propertySource.getProperty(name);
                    if (candidate != null) {
                        return candidate;
                    }
                }
            }

            return null;
        });
    }

    @Override
    public boolean containsProperty(String name) {
        return ConfigVersionManager.doWithVersion(version -> {
            VersionPropertySource<?> propertySource = null;
            for (int index = this.propertySources.size() - 1; index >= 0; index--) {
                propertySource = this.propertySources.get(index);

                if (propertySource.getVersion() <= version) {
                    if (propertySource.containsProperty(name)) {
                        return true;
                    }
                }
            }

            return false;
        });
    }

    @Override
    public String[] getPropertyNames() {
        return ConfigVersionManager.doWithVersion(version -> {
            Set<String> names = new LinkedHashSet<String>();

            VersionPropertySource<?> propertySource = null;
            for (int index = this.propertySources.size() - 1; index >= 0; index--) {
                propertySource = this.propertySources.get(index);

                if (propertySource.getVersion() <= version) {
                    names.addAll(Arrays.asList(propertySource.getPropertyNames()));
                }
            }

            return StringUtils.toStringArray(names);
        });
    }

    /**
     * Add the given {@link PropertySource} to the end of the chain.
     *
     * @param versionPropertySource the version PropertySource to add
     */
    public void addPropertySource(VersionPropertySource<?> versionPropertySource) {
        if (ConfigVersionManager.addVersion(versionPropertySource.getVersion())) {
            this.propertySources.add(versionPropertySource);
        }
    }

    /**
     * Return all property sources that this composite source holds.
     *
     * @since 4.1.1
     */
    public Collection<VersionPropertySource<?>> getPropertySources() {
        return this.propertySources;
    }

    @Override
    public String toString() {
        return String.format("%s [name='%s', propertySources=%s]", getClass().getSimpleName(), this.name, this.propertySources);
    }

}

@@ -1492,27 +1492,12 @@
     
-Object candidate = 
+if (
 prop
@@ -1499,35 +1499,40 @@
 (propertySource.
-get
+contains
 Property(name);%0A
@@ -1525,25 +1525,48 @@
 operty(name)
-;
+) %7B // %E7%89%88%E6%9C%AC%E4%B8%AD%E6%9C%89%E8%BF%99%E4%B8%AA%E5%B1%9E%E6%80%A7%EF%BC%8C%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%E5%B1%9E%E6%80%A7%E7%9A%84%E5%80%BC
 %0A           
@@ -1574,20 +1574,27 @@
         
-if (
+    Object 
 candidat
@@ -1599,18 +1599,64 @@
 ate 
-!
 = 
+propertySource.getProperty(name); // %E5%B7%B2%E7%BB%8F%E5%88%A0%E9%99%A4%E7%9A%84%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%B1%9E%E6%80%A7%E5%80%BC%E8%BF%94%E5%9B%9E
 null
-) %7B
 %0A   

修正配置属性删除时，客户端未生效，还能获取到最后一次的值的bug