package org.uberfire.backend.server.group;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import org.uberfire.backend.group.Group;
import org.uberfire.backend.group.GroupService;
import org.uberfire.backend.repositories.Repository;
import org.uberfire.backend.server.config.ConfigGroup;
import org.uberfire.backend.server.config.ConfigItem;
import org.uberfire.backend.server.config.ConfigType;
import org.uberfire.backend.server.config.ConfigurationFactory;
import org.uberfire.backend.server.config.ConfigurationService;

@ApplicationScoped
public class GroupServiceImpl implements GroupService {

    @Inject
    private ConfigurationService configurationService;

    @Inject
    private ConfigurationFactory configurationFactory;

    @Inject
    private GroupFactory groupFactory;

    private Map<String, Group> registeredGroups = new HashMap<String, Group>();

    @PostConstruct
    public void loadGroups() {
        Collection<ConfigGroup> groups = configurationService.getConfiguration( ConfigType.GROUP );
        if ( groups != null ) {
            for ( ConfigGroup groupConfig : groups ) {
                Group group = groupFactory.newGroup( groupConfig );
                registeredGroups.put( group.getName(),
                                      group );
            }
        }
    }

    @Override
    public Group getGroup( final String name ) {
        return registeredGroups.get( name );
    }

    @Override
    public Collection<Group> getGroups() {
        return Collections.unmodifiableCollection( registeredGroups.values() );
    }

    @Override
    public Group createGroup( final String name,
                              final String owner ) {
        final ConfigGroup groupConfig = configurationFactory.newConfigGroup( ConfigType.GROUP,
                                                                             name,
                                                                             "" );
        groupConfig.addConfigItem( configurationFactory.newConfigItem( "owner",
                                                                       owner ) );
        groupConfig.addConfigItem( configurationFactory.newConfigItem( "repositories",
                                                                       new ArrayList<String>() ) );
        groupConfig.addConfigItem( configurationFactory.newConfigItem( "security:roles",
                                                                       new ArrayList<String>() ) );
        configurationService.addConfiguration( groupConfig );
        return groupFactory.newGroup( groupConfig );
    }

    @Override
    public Group createGroup( final String name,
                              final String owner,
                              final Collection<Repository> repositories ) {
        final ConfigGroup groupConfig = configurationFactory.newConfigGroup( ConfigType.GROUP,
                                                                             name,
                                                                             "" );
        groupConfig.addConfigItem( configurationFactory.newConfigItem( "owner",
                                                                       owner ) );
        groupConfig.addConfigItem( configurationFactory.newConfigItem( "repositories",
                                                                       getRepositoryAliases( repositories ) ) );
        groupConfig.addConfigItem( configurationFactory.newConfigItem( "security:roles",
                                                                       new ArrayList<String>() ) );
        configurationService.addConfiguration( groupConfig );
        return groupFactory.newGroup( groupConfig );
    }

    private List<String> getRepositoryAliases( final Collection<Repository> repositories ) {
        final List<String> repositoryList = new ArrayList<String>();
        for ( Repository repo : repositories ) {
            repositoryList.add( repo.getAlias() );
        }
        return repositoryList;
    }

    @Override
    public void addRepository( final Group group,
                               final Repository repository ) {
        final ConfigGroup thisGroupConfig = findGroupConfig( group.getName() );

        if ( thisGroupConfig != null ) {
            ConfigItem<List> repositories = thisGroupConfig.getConfigItem( "repositories" );
            repositories.getValue().add( repository.getAlias() );

            configurationService.addConfiguration( thisGroupConfig );

            final Group updatedGroup = groupFactory.newGroup( thisGroupConfig );
            registeredGroups.put( updatedGroup.getName(),
                                  updatedGroup );
        } else {
            throw new IllegalArgumentException( "Group " + group.getName() + " not found" );
        }
    }

    @Override
    public void removeRepository( final Group group,
                                  final Repository repository ) {
        final ConfigGroup thisGroupConfig = findGroupConfig( group.getName() );

        if ( thisGroupConfig != null ) {
            final ConfigItem<List> repositories = thisGroupConfig.getConfigItem( "repositories" );
            repositories.getValue().remove( repository.getAlias() );

            configurationService.addConfiguration( thisGroupConfig );

            final Group updatedGroup = groupFactory.newGroup( thisGroupConfig );
            registeredGroups.put( updatedGroup.getName(),
                                  updatedGroup );
        } else {
            throw new IllegalArgumentException( "Group " + group.getName() + " not found" );
        }
    }

    @Override
    public void addRole( final Group group,
                         final String role ) {
        final ConfigGroup thisGroupConfig = findGroupConfig( group.getName() );

        if ( thisGroupConfig != null ) {
            final ConfigItem<List> roles = thisGroupConfig.getConfigItem( "security:roles" );
            roles.getValue().add( role );

            configurationService.addConfiguration( thisGroupConfig );

            final Group updatedGroup = groupFactory.newGroup( thisGroupConfig );
            registeredGroups.put( updatedGroup.getName(),
                                  updatedGroup );
        } else {
            throw new IllegalArgumentException( "Group " + group.getName() + " not found" );
        }
    }

    @Override
    public void removeRole( final Group group,
                            final String role ) {
        final ConfigGroup thisGroupConfig = findGroupConfig( group.getName() );

        if ( thisGroupConfig != null ) {
            final ConfigItem<List> roles = thisGroupConfig.getConfigItem( "security:roles" );
            roles.getValue().remove( role );

            configurationService.addConfiguration( thisGroupConfig );

            final Group updatedGroup = groupFactory.newGroup( thisGroupConfig );
            registeredGroups.put( updatedGroup.getName(),
                                  updatedGroup );
        } else {
            throw new IllegalArgumentException( "Group " + group.getName() + " not found" );
        }
    }

    protected ConfigGroup findGroupConfig( final String name ) {

        final Collection<ConfigGroup> groups = configurationService.getConfiguration( ConfigType.GROUP );
        if ( groups != null ) {
            for ( ConfigGroup groupConfig : groups ) {
                if ( groupConfig.getName().equals( name ) ) {
                    return groupConfig;
                }
            }
        }
        return null;
    }
}

@@ -2763,32 +2763,33 @@
 upConfig );%0A
+%0A
         
 return group
@@ -2768,38 +2768,54 @@
 fig );%0A%0A        
-return
+final Group newGroup =
  groupFactory.ne
@@ -2829,32 +2829,149 @@
  groupConfig );%0A
+        registeredGroups.put( newGroup.getName(),%0A                              newGroup );%0A        return newGroup;%0A
     %7D%0A%0A    @Over
@@ -4020,32 +4020,33 @@
 upConfig );%0A
+%0A
         
 return group
@@ -4029,30 +4029,46 @@
 );%0A%0A        
-return
+final Group newGroup =
  groupFactor
@@ -4090,24 +4090,141 @@
 upConfig );%0A
+        registeredGroups.put( newGroup.getName(),%0A                              newGroup );%0A        return newGroup;%0A
     %7D%0A%0A    p
@@ -7711,17 +7711,16 @@
 ame ) %7B%0A
-%0A
         

create methods were not caching new group