package com.orientechnologies.orient.core.sql;

import com.orientechnologies.orient.core.command.OCommandDistributedReplicateRequest;
import com.orientechnologies.orient.core.command.OCommandRequest;
import com.orientechnologies.orient.core.command.OCommandRequestText;
import com.orientechnologies.orient.core.exception.OCommandExecutionException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Creates a new user.
 * 
 * @author Matan Shukry (matanshukry@gmail.com)
 * @since 4/22/2015
 */
public class OCommandExecutorSQLCreateUser extends OCommandExecutorSQLAbstract implements OCommandDistributedReplicateRequest {
  public static final String  KEYWORD_CREATE      = "CREATE";
  public static final String  KEYWORD_USER        = "USER";
  public static final String  KEYWORD_IDENTIFIED  = "IDENTIFIED";
  public static final String  KEYWORD_BY          = "BY";
  public static final String  KEYWORD_ROLE        = "ROLE";
  public static final String  SYNTAX              = "CREATE USER <user-name> IDENTIFIED BY <user-password> [ ROLE <role-name> ]";

  private static final String USER_CLASS          = "OUser";
  private static final String USER_FIELD_NAME     = "name";
  private static final String USER_FIELD_PASSWORD = "password";
  private static final String USER_FIELD_STATUS   = "status";
  private static final String USER_FIELD_ROLES    = "roles";

  private static final String DEFAULT_STATUS      = "ACTIVE";
  private static final String DEFAULT_ROLE        = "writer";
  private static final String ROLE_CLASS          = "ORole";
  private static final String ROLE_FIELD_NAME     = "name";

  private String              userName;
  private String              pass;
  private List<String>        roles;

  @Override
  public OCommandExecutorSQLCreateUser parse(OCommandRequest iRequest) {
    init((OCommandRequestText) iRequest);

    parserRequiredKeyword(KEYWORD_CREATE);
    parserRequiredKeyword(KEYWORD_USER);
    this.userName = parserRequiredWord(false, "Expected <user-name>");

    parserRequiredKeyword(KEYWORD_IDENTIFIED);
    parserRequiredKeyword(KEYWORD_BY);
    this.pass = parserRequiredWord(false, "Expected <user-password>");

    this.roles = new ArrayList<String>();

    String temp;
    while ((temp = parseOptionalWord(true)) != null) {
      if (parserIsEnded()) {
        break;
      }

      if (temp.equals(KEYWORD_ROLE)) {
        String role = parserRequiredWord(false, "Expected <role-name>");
        int roleLen = (role != null) ? role.length() : 0;
        if (roleLen > 0) {
          if (role.charAt(0) == '[' && role.charAt(roleLen - 1) == ']') {
            role = role.substring(1, role.length() - 1);
            String[] splits = role.split("[, ]");
            for (String spl : splits) {
              if (spl.length() > 0) {
                this.roles.add(spl);
              }
            }
          } else {
            this.roles.add(role);
          }
        }
      }
    }

    return this;
  }

  @Override
  public Object execute(Map<Object, Object> iArgs) {
    if (this.userName == null) {
      throw new OCommandExecutionException("Cannot execute the command because it has not been parsed yet");
    }

    // Build following command:
    // INSERT INTO OUser SET name='<name>', password='<pass>', status='ACTIVE',
    // role=(SELECT FROM ORole WHERE name in ['<role1>', '<role2>', ...])

    // INSERT INTO OUser SET
    StringBuilder sb = new StringBuilder();
    sb.append("INSERT INTO ");
    sb.append(USER_CLASS);
    sb.append(" SET ");

    // name=<name>
    sb.append(USER_FIELD_NAME);
    sb.append("='");
    sb.append(this.userName);
    sb.append("'");

    // pass=<pass>
    sb.append(',');
    sb.append(USER_FIELD_PASSWORD);
    sb.append("='");
    sb.append(this.pass);
    sb.append("'");

    // status=ACTIVE
    sb.append(',');
    sb.append(USER_FIELD_STATUS);
    sb.append("='");
    sb.append(DEFAULT_STATUS);
    sb.append("'");

    // role=(select from ORole where name in [<input_role || 'writer'>)]
    if (this.roles.size() == 0) {
      this.roles.add(DEFAULT_ROLE);
    }

    sb.append(',');
    sb.append(USER_FIELD_ROLES);
    sb.append("=(SELECT FROM ");
    sb.append(ROLE_CLASS);
    sb.append(" WHERE ");
    sb.append(ROLE_FIELD_NAME);
    sb.append(" IN [");
    for (int i = 0; i < this.roles.size() - 1; ++i) {
      sb.append("'");
      sb.append(this.roles.get(i));
      sb.append("', ");
    }
    sb.append("'");
    sb.append(this.roles.get(this.roles.size() - 1));
    sb.append("'])");

    return getDatabase().command(new OCommandSQL(sb.toString())).execute();
  }

  @Override
  public String getSyntax() {
    return SYNTAX;
  }

  @Override
  public QUORUM_TYPE getQuorumType() {
    return QUORUM_TYPE.ALL;
  }
}

@@ -4356,20 +4356,16 @@
 s.size()
- - 1
 ; ++i) %7B
@@ -4361,24 +4361,45 @@
 e(); ++i) %7B%0A
+      if (i %3E 0) %7B%0A  
       sb.app
@@ -4399,29 +4399,133 @@
  sb.append(%22
-'
+, 
 %22);%0A
+      %7D%0A      String role = roles.get(i);%0A      if (role.startsWith(%22'%22) %7C%7C role.startsWith(%22%5C%22%22)) %7B%0A  
       sb.app
@@ -4558,32 +4558,21 @@
     
-sb.append(%22', %22);
+%7D else %7B
 %0A    
-%7D%0A
     
@@ -4583,24 +4583,28 @@
 ppend(%22'%22);%0A
+    
     sb.appen
@@ -4624,32 +4624,50 @@
 get(
-this.roles.size() - 1));
+i));%0A        sb.append(%22'%22);%0A      %7D%0A    %7D
 %0A   
@@ -4682,16 +4682,14 @@
 nd(%22
-'
 %5D)%22);%0A
-%0A
     

Fix CREATE USER command