package org.matrix.androidsdk;

import android.net.Uri;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.matrix.androidsdk.rest.model.login.Credentials;
import org.matrix.androidsdk.ssl.Fingerprint;

import java.util.ArrayList;


/**
 * Represents how to connect to a specific Homeserver, may include credentials to use.
 */
public class HomeserverConnectionConfig {
    private Uri mHsUri;
    private ArrayList<Fingerprint> mAllowedFingerprints;
    private Credentials mCredentials;
    private boolean mPin;

    /**
     * @param hsUri The URI to use to connect to the homeserver
     */
    public HomeserverConnectionConfig(Uri hsUri) {
        this(hsUri, null);
    }

    /**
     * @param hsUri The URI to use to connect to the homeserver
     * @param credentials The credentials to use, if needed. Can be null.
     */
    public HomeserverConnectionConfig(Uri hsUri, Credentials credentials) {
        this(hsUri, credentials, new ArrayList<Fingerprint>(), false);
    }

    /**
     * @param hsUri The URI to use to connect to the homeserver
     * @param credentials The credentials to use, if needed. Can be null.
     * @param allowedFingerprints If using SSL, allow server certs that match these fingerprints.
     * @param pin If true only allow certs matching given fingerprints, otherwise fallback to
     *            standard X509 checks.
     */
    public HomeserverConnectionConfig(Uri hsUri, Credentials credentials, ArrayList<Fingerprint> allowedFingerprints, boolean pin) {
        if (hsUri == null || (!"http".equals(hsUri.getScheme()) && !"https".equals(hsUri.getScheme())) ) {
            throw new RuntimeException("Invalid home server URI: "+hsUri);
        }

        this.mHsUri = hsUri;
        this.mAllowedFingerprints = allowedFingerprints;
        this.mPin = pin;
        this.mCredentials = credentials;
    }

    public Uri getHomeserverUri() { return mHsUri; }
    public ArrayList<Fingerprint> getAllowedFingerprints() { return mAllowedFingerprints; }

    public Credentials getCredentials() { return mCredentials; }
    public void setCredentials(Credentials credentials) { this.mCredentials = credentials; }


    /**
     * @return whether we should reject X509 certs that were issued by trusts CAs and only trust
     * certs with matching fingerprints.
     */
    public boolean shouldPin() {
        return mPin;
    }

    @Override
    public String toString() {
        return "HomeserverConnectionConfig{" +
                "mHsUri=" + mHsUri +
                ", mAllowedFingerprints size=" + mAllowedFingerprints.size() +
                ", mCredentials=" + mCredentials +
                ", mPin=" + mPin +
                '}';
    }

    public JSONObject toJson() throws JSONException {
        JSONObject json = new JSONObject();

        json.put("home_server_url", mHsUri.toString());
        json.put("pin", mPin);
        if (mCredentials != null) json.put("credentials", mCredentials.toJson());
        if (mAllowedFingerprints != null) {
            ArrayList<JSONObject> fingerprints = new ArrayList<JSONObject>(mAllowedFingerprints.size());

            for (Fingerprint fingerprint : mAllowedFingerprints) {
                fingerprints.add(fingerprint.toJson());
            }

            json.put("fingerprints", new JSONArray(fingerprints));
        }

        return json;
    }

    public static HomeserverConnectionConfig fromJson(JSONObject obj) throws JSONException {
        JSONArray fingerprintArray = obj.optJSONArray("fingerprints");
        ArrayList<Fingerprint> fingerprints = new ArrayList<Fingerprint>();
        if (fingerprintArray != null) {
            for (int i = 0; i < fingerprintArray.length(); i++) {
                fingerprints.add(Fingerprint.fromJson(fingerprintArray.getJSONObject(i)));
            }
        }

        JSONObject credentialsObj = obj.optJSONObject("credentials");
        Credentials creds = credentialsObj != null ? Credentials.fromJson(credentialsObj) : null;

        return new HomeserverConnectionConfig(
                Uri.parse(obj.getString("home_server_url")),
                creds,
                fingerprints,
                obj.optBoolean("pin", false)
        );
    }
}

@@ -429,24 +429,60 @@
 Uri mHsUri;%0A
+    private Uri mIdentityServerUri;%0A
     private 
@@ -1005,16 +1005,22 @@
 s(hsUri,
+ null,
  credent
@@ -1134,32 +1134,98 @@
  the homeserver%0A
+     * @param identityServerUri The URI to use to manage identity%0A
      * @param cr
@@ -1562,32 +1562,55 @@
 onfig(Uri hsUri,
+ Uri identityServerUri,
  Credentials cre
@@ -1883,211 +1883,687 @@
     
-this.mHsUri = hsUri;%0A        this.mAllowedFingerprints = allowedFingerprints;%0A        this.mPin = pin;%0A        this.mCredentials = credentials;%0A    %7D%0A%0A    public Uri getHomeserverUri() %7B return mHsUri; %7D
+if ((null != identityServerUri) && (!%22http%22.equals(hsUri.getScheme()) && !%22https%22.equals(hsUri.getScheme()))) %7B%0A            throw new RuntimeException(%22Invalid identity server URI: %22 + identityServerUri);%0A        %7D%0A%0A        this.mHsUri = hsUri;%0A        this.mIdentityServerUri = identityServerUri;%0A        this.mAllowedFingerprints = allowedFingerprints;%0A        this.mPin = pin;%0A        this.mCredentials = credentials;%0A    %7D%0A%0A    public Uri getHomeserverUri() %7B return mHsUri; %7D%0A%0A    public void setIdentityServerUri(Uri uri) %7B%0A        mIdentityServerUri = uri;%0A    %7D%0A    public Uri getIdentityServerUri() %7B return (null == mIdentityServerUri) ? mHsUri : mIdentityServerUri; %7D%0A
 %0A   
@@ -3156,16 +3156,77 @@
 HsUri +%0A
+                %22mIdentityServerUri=%22 + mIdentityServerUri +%0A
         
@@ -3561,24 +3561,101 @@
 oString());%0A
+        json.put(%22identity_server_url%22, getIdentityServerUri().toString());%0A%0A
         json
@@ -3673,16 +3673,17 @@
  mPin);%0A
+%0A
         
@@ -4789,22 +4789,51 @@
         
-return
+HomeserverConnectionConfig config =
  new Hom
@@ -4918,16 +4918,121 @@
 url%22)),%0A
+                obj.has(%22identity_server_url%22) ? Uri.parse(obj.getString(%22identity_server_url%22)) : null,%0A
         
@@ -5120,16 +5120,19 @@
 , false)
+);%0A
 %0A       
@@ -5132,17 +5132,29 @@
         
-)
+return config
 ;%0A    %7D%0A

Add identity server Url in the homeserver config.