/*
 * 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.program;

import org.hisp.dhis.android.core.data.database.DatabaseAdapter;

import java.util.List;

import static org.hisp.dhis.android.core.utils.Utils.isDeleted;

public class ProgramRuleHandler {
    private final ProgramRuleStore programRuleStore;
    private final ProgramRuleActionHandler programRuleActionHandler;

    ProgramRuleHandler(ProgramRuleStore programRuleStore,
                              ProgramRuleActionHandler programRuleActionHandler) {
        this.programRuleStore = programRuleStore;
        this.programRuleActionHandler = programRuleActionHandler;
    }

    public void handleProgramRules(List<ProgramRule> programRules) {
        if (programRules == null) {
            return;
        }

        deleteOrPersistProgramRules(programRules);
    }

    /**
     * Deletes or persists program rules and applies the changes to the database.
     * Has a nested call to deleteOrPersistProgramRuleActions
     *
     * @param programRules
     */
    private void deleteOrPersistProgramRules(List<ProgramRule> programRules) {
        int size = programRules.size();

        for (int i = 0; i < size; i++) {
            ProgramRule programRule = programRules.get(i);

            if (isDeleted(programRule)) {
                programRuleStore.delete(programRule.uid());
            } else {
                String programStageUid = null;
                if (programRule.programStage() != null) {
                    programStageUid = programRule.programStage().uid();
                }
                int updatedRow = programRuleStore.update(programRule.uid(), programRule.code(), programRule.name(),
                        programRule.displayName(), programRule.created(), programRule.lastUpdated(),
                        programRule.priority(), programRule.condition(), programRule.program().uid(),
                        programStageUid, programRule.uid());

                if (updatedRow <= 0) {
                    programRuleStore.insert(
                            programRule.uid(), programRule.code(), programRule.name(),
                            programRule.displayName(), programRule.created(), programRule.lastUpdated(),
                            programRule.priority(), programRule.condition(), programRule.program().uid(),
                            programStageUid);
                }
            }

            programRuleActionHandler.handleProgramRuleActions(programRule.programRuleActions());
        }
    }

    public static ProgramRuleHandler create(DatabaseAdapter databaseAdapter) {
        return new ProgramRuleHandler(
                new ProgramRuleStoreImpl(databaseAdapter),
                ProgramRuleActionHandler.create(databaseAdapter)
        );
    }
}

@@ -1590,16 +1590,187 @@
 ogram;%0A%0A
+import org.hisp.dhis.android.core.common.HandleAction;%0Aimport org.hisp.dhis.android.core.common.OrphanCleaner;%0Aimport org.hisp.dhis.android.core.common.OrphanCleanerImpl;%0A
 import o
@@ -2071,16 +2071,106 @@
 Handler;
+%0A    private final OrphanCleaner%3CProgramRule, ProgramRuleAction%3E programRuleActionCleaner;
 %0A%0A    Pr
@@ -2300,16 +2300,111 @@
 nHandler
+,%0A                       OrphanCleaner%3CProgramRule, ProgramRuleAction%3E programRuleActionCleaner
 ) %7B%0A    
@@ -2511,24 +2511,90 @@
 ionHandler;%0A
+        this.programRuleActionCleaner = programRuleActionCleaner;%0A
     %7D%0A%0A    p
@@ -3195,16 +3195,55 @@
 .get(i);
+%0A            HandleAction handleAction;
 %0A%0A      
@@ -3334,24 +3334,76 @@
 ule.uid());%0A
+                handleAction = HandleAction.Delete;%0A
             
@@ -3985,16 +3985,68 @@
 .uid());
+%0A                handleAction = HandleAction.Update;
 %0A%0A      
@@ -4467,16 +4467,72 @@
 geUid);%0A
+                    handleAction = HandleAction.Insert;%0A
         
@@ -4649,24 +4649,195 @@
 Actions());%0A
+            if (handleAction == HandleAction.Update) %7B%0A                programRuleActionCleaner.deleteOrphan(programRule, programRule.programRuleActions());%0A            %7D%0A
         %7D%0A  
@@ -5082,16 +5082,203 @@
 Adapter)
+,%0A                new OrphanCleanerImpl%3CProgramRule, ProgramRuleAction%3E(ProgramRuleActionModel.TABLE,%0A                        ProgramRuleActionModel.Columns.PROGRAM_RULE, databaseAdapter)
 %0A       

clean orphans before update