/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.syncope.core.policy;

import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.apache.syncope.core.persistence.beans.AbstractAttr;
import org.apache.syncope.core.persistence.beans.AbstractAttributable;
import org.apache.syncope.core.persistence.beans.Policy;
import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
import org.apache.syncope.types.AbstractPolicySpec;
import org.apache.syncope.types.AccountPolicySpec;
import org.apache.syncope.types.PasswordPolicySpec;

@Component
public class PolicyEvaluator {

    /**
     * Logger.
     */
    protected static final Logger LOG = LoggerFactory.getLogger(PolicyEvaluator.class);

    public <T extends AbstractPolicySpec> T evaluate(final Policy policy, final AbstractAttributable attributable) {

        T result = null;

        if (policy != null) {
            AbstractAttr attribute;
            List<String> values;

            switch (policy.getType()) {
                case PASSWORD:
                case GLOBAL_PASSWORD:
                    final PasswordPolicySpec pspec = policy.getSpecification();
                    final PasswordPolicySpec passwordPolicy = new PasswordPolicySpec();

                    BeanUtils.copyProperties(pspec, passwordPolicy, new String[] { "schemasNotPermitted" });

                    for (String schema : pspec.getSchemasNotPermitted()) {
                        attribute = attributable.getAttribute(schema);
                        if (attribute != null) {
                            values = attribute.getValuesAsStrings();
                            if (values != null && !values.isEmpty()) {
                                passwordPolicy.getWordsNotPermitted().add(values.get(0));
                            }
                        }
                    }

                    // Password history verification and update
                    final String password = ((SyncopeUser) attributable).getPassword();

                    final List<String> passwordHistory = ((SyncopeUser) attributable).getPasswordHistory();

                    if (((SyncopeUser) attributable).verifyPasswordHistory(((SyncopeUser) attributable)
                            .getClearPassword(), pspec.getHistoryLength())) {

                        passwordPolicy.getWordsNotPermitted().add(((SyncopeUser) attributable).getClearPassword());
                    } else {

                        if (pspec.getHistoryLength() > 0 && password != null) {
                            passwordHistory.add(password);
                        }

                        if (pspec.getHistoryLength() < passwordHistory.size()) {
                            for (int i = 0; i < passwordHistory.size() - pspec.getHistoryLength(); i++) {

                                passwordHistory.remove(i);
                            }
                        }
                    }

                    result = (T) passwordPolicy;
                    break;
                case ACCOUNT:
                case GLOBAL_ACCOUNT:
                    final AccountPolicySpec spec = policy.getSpecification();
                    final AccountPolicySpec accountPolicy = new AccountPolicySpec();

                    BeanUtils.copyProperties(spec, accountPolicy, new String[] { "schemasNotPermitted" });

                    for (String schema : spec.getSchemasNotPermitted()) {
                        attribute = attributable.getAttribute(schema);
                        if (attribute != null) {
                            values = attribute.getValuesAsStrings();
                            if (values != null && !values.isEmpty()) {
                                accountPolicy.getWordsNotPermitted().add(values.get(0));
                            }
                        }
                    }

                    result = (T) accountPolicy;
                    break;
                case SYNC:
                case GLOBAL_SYNC:
                    result = null;
                    break;
                default:
                    result = null;
            }
        }

        return result;
    }
}

@@ -842,16 +842,44 @@
 olicy;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -2214,35 +2214,33 @@
 cy, new String%5B%5D
- %7B 
+%7B
 %22schemasNotPermi
@@ -2236,33 +2236,32 @@
 masNotPermitted%22
- 
 %7D);%0A%0A           
@@ -2817,16 +2817,17 @@
  update%0A
+%0A
         
@@ -2842,33 +2842,343 @@
     
-final String password
+if (!(attributable instanceof SyncopeUser)) %7B%0A                        LOG.error(%22Cannot check previous passwords. attributable is not a user object: %22 + attributable.getClass().toString());%0A                        result = (T) passwordPolicy;%0A                        break;%0A                    %7D%0A                    SyncopeUser user
  = 
-(
 (Syn
@@ -3191,33 +3191,82 @@
 er) attributable
-)
+;%0A                    final String password = user
 .getPassword();%0A
@@ -3261,25 +3261,24 @@
 Password();%0A
-%0A
             
@@ -3326,36 +3326,12 @@
 y = 
-((SyncopeUser) attributable)
+user
 .get
@@ -3378,116 +3378,39 @@
 if (
-((SyncopeUser) attributable).verifyPasswordHistory(((SyncopeUser) attributable)%0A                            
+user.verifyPasswordHistory(user
 .get
@@ -3451,25 +3451,24 @@
 ength())) %7B%0A
-%0A
             
@@ -3525,36 +3525,12 @@
 add(
-((SyncopeUser) attributable)
+user
 .get
@@ -3576,17 +3576,16 @@
  else %7B%0A
-%0A
         
@@ -3733,33 +3733,32 @@
               %7D%0A
-%0A
                 
@@ -3924,25 +3924,24 @@
 h(); i++) %7B%0A
-%0A
             
@@ -4057,33 +4057,32 @@
               %7D%0A
-%0A
                 
@@ -4454,11 +4454,9 @@
 ng%5B%5D
- %7B 
+%7B
 %22sch
@@ -4472,17 +4472,16 @@
 rmitted%22
- 
 %7D);%0A%0A   

fix unchecked casts