/**
*
* Copyright
* 2009-2015 Jayway Products AB
* 2016-2017 Föreningen Sambruk
*
* Licensed under AGPL, Version 3.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.gnu.org/licenses/agpl.txt
*
* 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 se.streamsource.streamflow.web.domain.structure.form;
import org.qi4j.api.common.Optional;
import org.qi4j.api.concern.ConcernOf;
import org.qi4j.api.concern.Concerns;
import org.qi4j.api.entity.Aggregated;
import org.qi4j.api.entity.EntityBuilder;
import org.qi4j.api.entity.Identity;
import org.qi4j.api.entity.IdentityGenerator;
import org.qi4j.api.entity.association.ManyAssociation;
import org.qi4j.api.injection.scope.Service;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.injection.scope.This;
import org.qi4j.api.mixin.Mixins;
import org.qi4j.api.specification.Specification;
import org.qi4j.api.structure.Module;
import org.qi4j.api.util.Iterables;
import org.qi4j.library.constraints.annotation.GreaterThan;
import se.streamsource.streamflow.api.ErrorResources;
import se.streamsource.streamflow.infrastructure.event.domain.DomainEvent;
import se.streamsource.streamflow.util.Strings;
import se.streamsource.streamflow.web.domain.Describable;
/**
* JAVADOC
*/
@Mixins(Pages.Mixin.class)
@Concerns( Pages.MoveConcern.class )
public interface Pages
{
Page createPage( String name );
void removePage( Page page );
void movePage( Page page, @GreaterThan(-1) Integer toIdx );
Page getPageByName( String name );
interface Data
{
@Aggregated
ManyAssociation<Page> pages();
Page createdPage( @Optional DomainEvent event, String id );
void removedPage( @Optional DomainEvent event, Page Page );
void movedPage( @Optional DomainEvent event, Page page, int toIdx );
}
abstract class Mixin
implements Pages, Data
{
@Service
IdentityGenerator idGen;
@Structure
Module module;
@This
Data data;
public Page createPage( String name )
{
Page Page = createdPage( null, idGen.generate( Identity.class ) );
Page.changeDescription( name );
return Page;
}
public void removePage( Page page )
{
if (!data.pages().contains( page ))
return;
removedPage( null, page );
}
public void movePage( Page page, Integer toIdx )
{
if (!data.pages().contains( page ) || data.pages().count() <= toIdx)
return;
movedPage( null, page, toIdx );
}
public Page getPageByName( String name )
{
for (Page page : data.pages())
{
if (((Describable.Data) page).description().get().equals( name ))
return page;
}
return null;
}
public Page createdPage( @Optional DomainEvent event, String id )
{
EntityBuilder<Page> builder = module.unitOfWorkFactory().currentUnitOfWork().newEntityBuilder( Page.class, id );
Page page = builder.newInstance();
data.pages().add( page );
return page;
}
public void movedPage( @Optional DomainEvent event, Page page, int toIdx )
{
data.pages().remove( page );
data.pages().add( toIdx, page );
}
public void removedPage( @Optional DomainEvent event, Page page )
{
data.pages().remove( page );
}
}
abstract class MoveConcern
extends ConcernOf<Pages>
implements Pages
{
@This Pages.Data pages;
public void movePage( Page page, @GreaterThan(-1) Integer toIdx )
{
if( ruleViolation( page, toIdx ) )
{
throw new IllegalArgumentException( ErrorResources.form_move_page_rule_violation.name() );
} else
{
next.movePage( page, toIdx );
}
}
/**
* Check if a move would result in a rule violation.
* A page with a rule may not be moved to a location before the target field of the rule!
* A page may not switch place with a page that has the target field as rule!
* @param page The page to be moved
* @param toIdx The index to move to
* @return Whether the move will result in a rule violation or not.
*/
private boolean ruleViolation(final Page page, Integer toIdx )
{
final Page moveTo = pages.pages().get( toIdx.intValue() );
boolean returnValue = false;
if( page.getRule() != null && !Strings.empty( page.getRule().field().get() ) )
{
returnValue = Iterables.count( Iterables.filter( new Specification<Field>()
{
public boolean satisfiedBy( Field field )
{
return ((Identity)field).identity().get().equals( page.getRule().field().get() );
}
}, ((Fields.Data)moveTo).fields() ) ) > 0;
} else if( moveTo.getRule() != null && !Strings.empty( moveTo.getRule().field().get() ) )
{
returnValue = Iterables.count( Iterables.filter( new Specification<Field>()
{
public boolean satisfiedBy( Field field )
{
return ((Identity)field).identity().get().equals( moveTo.getRule().field().get() );
}
}, ((Fields.Data)page).fields() ) ) > 0;
}
return returnValue;
}
}
}