package com.github.kongchen.swagger.docgen.mavenplugin;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.kongchen.swagger.docgen.GenerateException;
import io.swagger.models.auth.ApiKeyAuthDefinition;
import io.swagger.models.auth.BasicAuthDefinition;
import io.swagger.models.auth.OAuth2Definition;
import io.swagger.models.auth.SecuritySchemeDefinition;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @author chekong on 15/5/5.
 */
public class SecurityDefinition {
    private String name;
    private String type;
    private String in;
    private String description;
    private String json;
    private String jsonPath;

    public Map<String, SecuritySchemeDefinition> generateSecuritySchemeDefinitions() throws GenerateException {
        Map<String, SecuritySchemeDefinition> map = new HashMap<String, SecuritySchemeDefinition>();

        List<JsonNode> securityDefinitions = new ArrayList<JsonNode>();
        if (json != null || jsonPath != null) {
            securityDefinitions = loadSecurityDefintionsFromJsonFile();
        } else {
            securityDefinitions.add(new ObjectMapper().valueToTree(this));
        }

        for (JsonNode securityDefinition : securityDefinitions) {
            SecuritySchemeDefinition ssd = getSecuritySchemeDefinitionByType(securityDefinition.get("type").asText(), securityDefinition);
            if (ssd != null) {
                map.put(securityDefinition.get("name").asText(), ssd);
            }
        }

        return map;
    }

    private List<JsonNode> loadSecurityDefintionsFromJsonFile() throws GenerateException {
        List<JsonNode> securityDefinitions = new ArrayList<JsonNode>();

        try {
            InputStream jsonStream = json != null ? this.getClass().getResourceAsStream(json) : new FileInputStream(jsonPath);
            JsonNode tree = new ObjectMapper().readTree(jsonStream);
            Iterator<String> securityDefinitionNameIterator = tree.fieldNames();
            while (securityDefinitionNameIterator.hasNext()) {
                String securityDefinitionName = securityDefinitionNameIterator.next();
                JsonNode securityDefinition = tree.get(securityDefinitionName);
                securityDefinition = ((ObjectNode) securityDefinition).put("name", securityDefinitionName);
                securityDefinitions.add(securityDefinition);
            }
        } catch (IOException e) {
            throw new GenerateException(e);
        }

        return securityDefinitions;
    }

    private SecuritySchemeDefinition getSecuritySchemeDefinitionByType(String type, JsonNode node) throws GenerateException {
        try {
            ObjectMapper mapper = new ObjectMapper();
            SecuritySchemeDefinition def = null;
            if (type.equals(new OAuth2Definition().getType())) {
                def = new OAuth2Definition();
                if (node != null) {
                    def = mapper.readValue(node.traverse(), OAuth2Definition.class);
                }
            } else if (type.equals(new BasicAuthDefinition().getType())) {
                def = new BasicAuthDefinition();
                if (node != null) {
                    def = mapper.readValue(node.traverse(), BasicAuthDefinition.class);
                }
            } else if (type.equals(new ApiKeyAuthDefinition().getType())) {
                def = new ApiKeyAuthDefinition();
                if (node != null) {
                    def = mapper.readValue(node.traverse(), ApiKeyAuthDefinition.class);
                }
            }
            return def;
        } catch (IOException e) {
            throw new GenerateException(e);
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getIn() {
        return in;
    }

    public void setIn(String in) {
        this.in = in;
    }
}

@@ -579,17 +579,72 @@
 va.util.
-*
+HashMap;%0Aimport java.util.Iterator;%0Aimport java.util.Map
 ;%0A%0A/**%0A 
@@ -1084,37 +1084,44 @@
 on%3E();%0A%0A        
-List%3C
+Map%3CString, 
 JsonNode%3E securi
@@ -1136,34 +1136,40 @@
 tions = new 
-ArrayList%3C
+HashMap%3CString, 
 JsonNode%3E();
@@ -1322,32 +1322,24 @@
     
-securityDefinitions.add(
+JsonNode tree = 
 new 
@@ -1370,16 +1370,85 @@
 ee(this)
+;%0A            securityDefinitions.put(tree.get(%22name%22).asText(), tree
 );%0A     
@@ -1466,24 +1466,42 @@
    for (
+Map.Entry%3CString, 
 JsonNode
  securit
@@ -1484,32 +1484,33 @@
 String, JsonNode
+%3E
  securityDefinit
@@ -1534,20 +1534,96 @@
 initions
+.entrySet()
 ) %7B%0A
+            JsonNode definition = securityDefinition.getValue();%0A
         
@@ -1691,25 +1691,17 @@
 nByType(
-securityD
+d
 efinitio
@@ -1724,25 +1724,17 @@
 Text(), 
-securityD
+d
 efinitio
@@ -1810,39 +1810,27 @@
 finition.get
-(%22name%22).asText
+Key
 (), ssd);%0A  
@@ -1891,21 +1891,28 @@
 private 
-List%3C
+Map%3CString, 
 JsonNode
@@ -1985,21 +1985,28 @@
         
-List%3C
+Map%3CString, 
 JsonNode
@@ -2037,18 +2037,24 @@
 new 
-ArrayList%3C
+HashMap%3CString, 
 Json
@@ -2298,46 +2298,43 @@
 tor%3C
-String%3E securityDefinitionNameIterator
+Map.Entry%3CString, JsonNode%3E%3E fields
  = t
@@ -2342,20 +2342,16 @@
 ee.field
-Name
 s();%0A   
@@ -2368,259 +2368,272 @@
 hile
- (securityDefinitionNameIterator.hasNext()) %7B%0A                String securityDefinitionName = securityDefinitionNameIterator.next();%0A                JsonNode securityDefinition = tree.get(securityDefinitionName);%0A                securityDefinition
+(fields.hasNext()) %7B%0A                Map.Entry%3CString, JsonNode%3E field = fields.next();%0A                JsonNode securityDefinition = field.getValue();%0A%0A                if (!securityDefinition.hasNonNull(%22name%22)) %7B%0A                    ObjectNode modifieableNode
  = 
-(
 (Obj
@@ -2663,105 +2663,187 @@
 tion
-).put(%22name%22, securityDefinitionName);%0A                securityDefinitions.add(securityDefinition
+;%0A                    securityDefinition = modifieableNode.put(%22name%22, field.getKey());%0A                %7D%0A%0A                securityDefinitions.put(field.getKey(), field.getValue()
 );%0A 

Fix Securitydefinitions having wrong name This prevents the name field be used as overall name of the definition itself. fixes #616