package me.chyxion.tigon.shiro;

import java.util.*;
import lombok.Getter;
import java.io.IOException;
import java.io.InputStream;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.PostConstruct;
import org.springframework.core.io.Resource;

/**
 * @author Donghuang <br>
 * donghuang@wacai.com <br>
 * Jun 27, 2018 10:42
 */
@Slf4j
@Getter
public class FilterChainDefinitionMap extends LinkedHashMap<String, String> {
   private final Resource configLocation;

    public FilterChainDefinitionMap(final Resource configLocation) {
        this.configLocation = configLocation;
    }

    public FilterChainDefinitionMap(final Resource configLocation, final Map<String, String> map) {
        super(map);
        this.configLocation = configLocation;
    }

    @PostConstruct
    void init() throws IOException {
       log.info("Load shiro filter chain definition from config location [{}].", configLocation);

       if (configLocation != null && configLocation.exists()) {
            final InputStream authIn = configLocation.getInputStream();
            if (authIn != null) {
                final Properties props = new OrderedProperties();
                try {
                    props.load(authIn);
                }
                catch (final IOException e) {
                    throw new IllegalStateException(
                        "Load shiro filter chain definition config error caused", e);
                }
                finally {
                    if (authIn != null) {
                        try {
                            authIn.close();
                        }
                        catch (IOException e) {
                            // ignore
                        }
                    }
                }

                for (final String path : props.stringPropertyNames()) {
                    final String auth = props.getProperty(path);
                    log.info("Shiro filter chain definition [{}] -> [{}] added.", path, auth);
                    put(path, auth);
                }
            }
            else {
                log.info("No input stream load from shiro filter chain definition config location [{}], ignore.", configLocation);
            }
       }
       else {
           log.info("Shiro filter chain definition config location [{}] does not exist, ignore.", configLocation);
       }
   }

   @Slf4j
   static class OrderedProperties extends Properties {
      private static final long serialVersionUID = 1L;
      private final Set<String> keys = new LinkedHashSet<>();

      /**
       * {@inheritDoc}
       */
      @Override
      public Object put(Object key, Object value) {
            log.debug("Load shiro filter chain [{}] -> [{}].", key, value);
            keys.add((String) key);
            return super.put(key, value);
      }

      /**
       * {@inheritDoc}
       */
      @Override
      @SuppressWarnings({ "rawtypes", "unchecked" })
      public Set keySet() {
         return keys;
      }

      /**
       * {@inheritDoc}
       */
      @Override
      public Set<String> stringPropertyNames() {
         return keys;
      }
   }
}
