/*
 * Copyright (c) 2017, University of Oslo
 *
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * Neither the name of the HISP project nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.hisp.dhis.android.core.organisationunit;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import org.hisp.dhis.android.core.common.HandleAction;
import org.hisp.dhis.android.core.common.IdentifiableHandlerImpl;
import org.hisp.dhis.android.core.common.IdentifiableObjectStore;
import org.hisp.dhis.android.core.common.ObjectWithoutUidStore;
import org.hisp.dhis.android.core.data.database.DatabaseAdapter;
import org.hisp.dhis.android.core.program.Program;
import org.hisp.dhis.android.core.user.User;
import org.hisp.dhis.android.core.user.UserOrganisationUnitLinkModel;
import org.hisp.dhis.android.core.user.UserOrganisationUnitLinkModelBuilder;
import org.hisp.dhis.android.core.user.UserOrganisationUnitLinkStore;

import java.util.List;
import java.util.Set;

public class OrganisationUnitHandler extends IdentifiableHandlerImpl<OrganisationUnit, OrganisationUnitModel> {
    private final ObjectWithoutUidStore<UserOrganisationUnitLinkModel> userOrganisationUnitLinkStore;
    private final ObjectWithoutUidStore<OrganisationUnitProgramLinkModel> organisationUnitProgramLinkStore;
    private final Set<String> programUids;
    private final OrganisationUnitModel.Scope scope;
    private final User user;

    public OrganisationUnitHandler(@NonNull IdentifiableObjectStore<OrganisationUnitModel> organisationUnitStore,
                                   @NonNull ObjectWithoutUidStore<UserOrganisationUnitLinkModel>
                                           userOrganisationUnitLinkStore,
                                   @NonNull ObjectWithoutUidStore<OrganisationUnitProgramLinkModel>
                                           organisationUnitProgramLinkStore,
                                   @Nullable Set<String> programUids,
                                   @Nullable OrganisationUnitModel.Scope scope,
                                   @Nullable User user) {
        super(organisationUnitStore);
        this.userOrganisationUnitLinkStore = userOrganisationUnitLinkStore;
        this.organisationUnitProgramLinkStore = organisationUnitProgramLinkStore;
        this.programUids = programUids;
        this.scope = scope;
        this.user = user;
    }

    @Override
    protected void afterObjectHandled(OrganisationUnit organisationUnit, HandleAction action) {
        UserOrganisationUnitLinkModelBuilder modelBuilder = new UserOrganisationUnitLinkModelBuilder(scope, user);
        userOrganisationUnitLinkStore.updateOrInsertWhere(modelBuilder.buildModel(organisationUnit));

        addOrganisationUnitProgramLink(organisationUnit);
    }

    private void addOrganisationUnitProgramLink(@NonNull OrganisationUnit organisationUnit) {
        List<Program> orgUnitPrograms = organisationUnit.programs();
        if (orgUnitPrograms != null && programUids != null) {
            OrganisationUnitProgramLinkModelBuilder modelBuilder
                    = new OrganisationUnitProgramLinkModelBuilder(organisationUnit);
            for (Program program : orgUnitPrograms) {
                if (programUids.contains(program.uid())) {
                    organisationUnitProgramLinkStore.updateOrInsertWhere(modelBuilder.buildModel(program));
                }
            }
        }
    }

    public static OrganisationUnitHandler create(DatabaseAdapter databaseAdapter,
                                                 Set<String> programUids,
                                                 OrganisationUnitModel.Scope scope,
                                                 User user) {
        return new OrganisationUnitHandler(
                OrganisationUnitStore.create(databaseAdapter),
                UserOrganisationUnitLinkStore.create(databaseAdapter),
                OrganisationUnitProgramLinkStore.create(databaseAdapter),
                programUids, scope, user);
    }
}

@@ -1870,24 +1870,146 @@
 bjectStore;%0A
+import org.hisp.dhis.android.core.common.LinkModelHandler;%0Aimport org.hisp.dhis.android.core.common.LinkModelHandlerImpl;%0A
 import org.h
@@ -2435,24 +2435,52 @@
 LinkStore;%0A%0A
+import java.util.ArrayList;%0A
 import java.
@@ -2745,38 +2745,42 @@
 e final 
-ObjectWithoutUidStore%3C
+LinkModelHandler%3CProgram, 
 Organisa
@@ -2828,29 +2828,31 @@
 tProgramLink
-Store
+Handler
 ;%0A    privat
@@ -3296,38 +3296,42 @@
 NonNull 
-ObjectWithoutUidStore%3C
+LinkModelHandler%3CProgram, 
 Organisa
@@ -3422,29 +3422,31 @@
 tProgramLink
-Store
+Handler
 ,%0A          
@@ -3797,21 +3797,23 @@
 gramLink
-Store
+Handler
  = organ
@@ -3830,29 +3830,31 @@
 tProgramLink
-Store
+Handler
 ;%0A        th
@@ -4578,143 +4578,54 @@
     
-OrganisationUnitProgramLinkModelBuilder modelBuilder%0A                    = new OrganisationUnitProgramLinkModelBuilder(organisationUnit
+List%3CProgram%3E programsToAdd = new ArrayList%3C%3E(
 );%0A 
@@ -4760,127 +4760,330 @@
     
-organisationUnitProgramLinkStore.updateOrInsertWhere(modelBuilder.buildModel(program));%0A                %7D%0A            %7D
+programsToAdd.add(program);%0A                %7D%0A            %7D%0A%0A            OrganisationUnitProgramLinkModelBuilder modelBuilder%0A                    = new OrganisationUnitProgramLinkModelBuilder(organisationUnit);%0A            organisationUnitProgramLinkHandler.handleMany(organisationUnit.uid(), programsToAdd, modelBuilder);
 %0A   
@@ -5568,32 +5568,125 @@
 tabaseAdapter),%0A
+                new LinkModelHandlerImpl%3CProgram, OrganisationUnitProgramLinkModel%3E(%0A        
                 
@@ -5733,32 +5733,33 @@
 databaseAdapter)
+)
 ,%0A              
@@ -5794,9 +5794,8 @@
 %0A    %7D%0A%7D
-%0A

use linkHandler on OrganisationUnitHandler