/*
 * Syncany, www.syncany.org
 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.syncany.tests.integration.scenarios;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.syncany.tests.util.TestAssertUtil.assertFileListEquals;

import org.junit.Ignore;
import org.junit.Test;
import org.syncany.plugins.transfer.TransferSettings;
import org.syncany.tests.util.TestClient;
import org.syncany.tests.util.TestConfigUtil;

/*
 * This test class uses tests one scenario using the DatabaseVersionUpdateDetector.
 * The algorithm used is described in the respective class ('algorithm B').
 *  
 * ////////////////////////////////////////////////////////////////////////////////////////////////////
 * 
 * TEST SCENARIO 
 * ----------------------------------------------------------------------------------------------------
 * T is the local timestamp, A/B/C are clients/machines, "-->" is a "sync up" operation,
 * "<--" is a "sync down" operation, "(CONFLICT X)" describes the comparison to be taken
 * and is described in detail below.
 * ----------------------------------------------------------------------------------------------------
 * T    A                       B                      C                        Remote Storage
 * ----------------------------------------------------------------------------------------------------
 *      
 * 01                                                  (  ,  ,C1)/T=01 -------> db-c-1
 * 02                                                  (  ,  ,C2)/T=02         
 * 03                                                  (  ,  ,C3)/T=03 -------> db-c-3
 * 04                           (  ,  ,C1)/T=01 <
 * 04                           (  ,  ,C2)/T=02 <
 * 04                           (  ,  ,C3)/T=03 <------------------------------ db-c-1, db-c-3
 * 05                                                  (  ,  ,C4)/T=05 -------> db-c-4
 * 06   (  ,  ,C1)/T=01 <
 * 06   (  ,  ,C2)/T=02 <
 * 06   (  ,  ,C3)/T=03 <
 * 06   (  ,  ,C4)/T=05 <------------------------------------------------------ db-c-1, db-c-3, db-c-4
 * 07                           (  ,B1,C3)/T=07 ------------------------------> db-b-1
 * 08   (A1,  ,C4)/T=08 
 * 09   (A2,  ,C4)/T=09 
 * 10   (A3,  ,C4)/T=10 ------------------------------------------------------> db-a-3
 * 
 *                              (CONFLICT 1) <--------------------------------- db-c-4, db-a-3
 *                              (A3,  ,C4)/T=10 wins
 *                              (A3,B2,C4)/T=.. after merge
 *                              To be uploaded
 *                        
 *      (CONFLICT 2) <--------------------------------------------------------- db-b-1
 *      (A3,  ,C4)/T=10 wins
 *      That's me. Do nothing.
 *      
 *                                                     (CONFLICT 3) <---------- db-a-3, db-b-1
 *                                                     (A3,  ,C4)/T=10 wins
 *                                                     To be applied locally
 *                              
 * 11   (A4,  ,C4)/T=11 
 * 12   (A5,  ,C4)/T=12 ------------------------------------------------------> db-a-5
 * 13                                                  (A3,  ,C5)/T=13 -------> db-c-5
 * 14                                                  (A3,  ,C6)/T=14         
 * 15                                                  (A3,  ,C7)/T=15 -------> db-c-7
 * 16                           (A3,B2,C4)/T=16                                        
 * 17                           (A3,B3,C4)/T=17 
 * 18                           (A3,B4,C4)/T=18 ------------------------------> db-b-4
 * 19   (A6,  ,C4)/T=19 ------------------------------------------------------> db-a-6
 * 20                           (A3,B5,C4)/T=20 ------------------------------> db-b-5
 * 21                                                  (A3,  ,C8)/T=21 -------> db-c-8
 * 
 *                              (CONFLICT 4) <--------------------------------- db-a-5, db-c-5, db-c-7, db-a-6, db-c-8
 *                              (A6,  ,C4)/T=19 wins
 *                              (A6,B6,C4)/T=.. after merge
 *                              To be uploaded
 * 
 *      (CONFLICT 5) <--------------------------------------------------------- db-c-5, db-c-7, db-b-4, db-b-5, db-c-8
 *      (A6,  ,C4)/T=10 wins
 *      That's me. Do nothing.
 *      
 *                                                     (CONFLICT 6) <---------- db-a-5, db-b-4, db-a-6, db-b-5
 *                                                     (A6,  ,C4)/T=19 wins
 *                                                     (A6,  ,C9)/T=.. after merge
 *                                                     To be uploaded	                                                     
 *                                                     
 * 22                                                  (A6,  ,C9)/T=22 -------> db-c-9
 * 23                           (A6,B6,C4)/T=23 ------------------------------> db-b-6
 * 
 *                                                     (CONFLICT 7) <---------- db-b-1, db-b-4, db-b-5, db-b-6, db-b-9
 *                                                     	                                                     
 *                              (CONFLICT 8) <--------------------------------- db-c-9
 *                              
 *      (CONFLICT 9) <--------------------------------------------------------- db-b-6, db-c-9
 *      
 * ////////////////////////////////////////////////////////////////////////////////////////////////////
 *      
 * CONFLICT 1 at B: 
 *  - Local:     (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03     
 *               (  ,B1,C3)/T=07 (last B)
 *  - db-c-4:    (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,  ,C4)/T=05 (last C)
 *  - db-a-3:    (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,  ,C4)/T=05
 *               (A1,  ,C4)/T=08
 *               (A2,  ,C4)/T=09
 *               (A3,  ,C4)/T=10 (last A)
 *               
 *  - Last versions conflicts:                (  ,B1,C3)/T=07 || (  ,  ,C4)/T=05
 *                                            (  ,B1,C3)/T=07 || (A3,  ,C4)/T=10  
 *  - Last common version between clients:    (  ,  ,C3)/T=03
 *  - First conflicting version per client:   (  ,  ,C4)/T=05 (first conflicting A)
 *                                            (  ,B1,C3)/T=07 (first conflicting B)
 *                                            (  ,  ,C4)/T=05 (first conflicting C)
 *  - Winner of first conflicting versions:   (  ,  ,C4)/T=05
 *  - Winning clients histories:              A                  C
 *                                            (  ,  ,C4)/T=05    (  ,  ,C4)/T=05
 *                                            (A1,  ,C4)/T=08    (empty)
 *                                            (A2,  ,C4)/T=09
 *                                            (A3,  ,C4)/T=10
 *  - Conflicts in winning histories:         (empty)
 *  - Winning histories lengths               A                  C
 *                                            4                  1
 *  - Follow this history (ultimate winner):  A 
 *                                            
 *  - Result:
 *     Winner: (A3,  ,C4)/T=10 
 *     --> Conflicts with local version
 *     --> Local must merge local version (  ,B1,C3) in (A3,  ,C4)
 *     --> Local result is then (A3,B2,C4)		  
 *     
 * CONFLICT 2 at A: 
 *  - Local:     (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (A3,  ,C4)/T=10 (last A)
 *  - db-b-1:    (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,B1,C3)/T=07 (last B)
 *               
 *  - Last versions conflicts:                (  ,B1,C3)/T=07 || (A3,  ,C4)/T=10
 *  - Last common version between clients:    (  ,  ,C3)/T=03 
 *  - First conflicting version per client:   (  ,  ,C4)/T=05 (first conflicting A)
 *                                            (  ,B1,C3)/T=07 (first conflicting B)
 *  - Winner of first conflicting versions:   (  ,  ,C4)/T=05
 *  - Winning clients histories:              A                   
 *                                            (  ,  ,C4)/T=05     
 *                                            (A1,  ,C4)/T=08    
 *                                            (A2,  ,C4)/T=09
 *                                            (A3,  ,C4)/T=10
 *  - Conflicts in winning histories:         (empty)
 *  - Winning histories lengths               4   
 *  - Follow this history (ultimate winner):  A 
 *                                            
 *  - Result:
 *     Winner: (A3,  ,C4)/T=10 
 *     --> That's me. Do nothing.     
 *     
 * CONFLICT 3 at C: 
 *  - Local:     (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,  ,C4)/T=05 (last C)
 *  - db-b-1:    (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,B1,C3)/T=07 (last B)
 *  - db-a-3:    (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,  ,C4)/T=05
 *               (A1,  ,C4)/T=08
 *               (A2,  ,C4)/T=09
 *               (A3,  ,C4)/T=10 (last A)
 *               
 *  - Last versions conflicts:                (  ,B1,C3)/T=07 || (A3,  ,C4)/T=10
 *  - Last common version between clients:    (  ,  ,C3)/T=03
 *  - First conflicting version per client:   (  ,  ,C4)/T=05 (first conflicting A)
 *                                            (  ,B1,C3)/T=07 (first conflicting B)
 *                                            (  ,  ,C4)/T=05 (first conflicting C)
 *  - Winner of first conflicting versions:   (  ,  ,C4)/T=05
 *  - Winning clients histories:              A                  C
 *                                            (  ,  ,C4)/T=05    (  ,  ,C4)/T=05
 *                                            (A1,  ,C4)/T=08    (empty)
 *                                            (A2,  ,C4)/T=09
 *                                            (A3,  ,C4)/T=10
 *  - Conflicts in winning histories:         (empty)
 *  - Winning histories lengths               A                  C
 *                                            4                  1
 *  - Follow this history (ultimate winner):  A 
 *                                            
 *  - Result:
 *     Winner: (A3,  ,C4)/T=10 
 *     --> That's not me. Must apply changes locally.     
 *     
 * CONFLICT 4 at B: 
 *  - Local:     (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,B1,C3)/T=07                         
 *               (A3,B2,C4)/T=16 (first conflict B)      
 *               (A3,B3,C4)/T=17
 *               (A3,B4,C4)/T=18
 *               (A3,B5,C4)/T=20 (last B)
 *  - db-a-5:    (A4,  ,C4)/T=11 (first conflict A)
 *               (A5,  ,C4)/T=12
 *  - db-a-6:    (A6,  ,C4)/T=19 (last A)
 *  - db-c-5:    (A3,  ,C5)/T=13 (first conflict C)
 *  - db-c-7:    (A3,  ,C6)/T=14
 *               (A3,  ,C7)/T=15
 *  - db-c-8:    (A3,  ,C8)/T=21 (last C)
 *               
 *  - Last versions conflicts:                (A3,B5,C4)/T=20 || (A6,  ,C4)/T=19
 *                                            (A3,B5,C4)/T=20 || (A3,  ,C8)/T=21
 *                                            (A6,  ,C4)/T=19 || (A3,  ,C8)/T=21
 *  - Last common version between clients:    (empty)
 *  - First conflicting version per client:   (A4,  ,C4)/T=11 (first conflicting A)
 *                                            (A3,B2,C4)/T=16 (first conflicting B)
 *                                            (A3,  ,C5)/T=13 (first conflicting C)
 *  - Winner of first conflicting versions:   (A4,  ,C4)/T=11
 *  - Winning clients histories:              A               
 *                                            (A4,  ,C4)/T=11 
 *                                            (A5,  ,C4)/T=12 
 *                                            (A6,  ,C4)/T=19
 *  - Conflicts in winning histories:         (empty)
 *  - Winning histories lengths               (not relevant)
 *  - Follow this history (ultimate winner):  A 
 *                                            
 *  - Result:
 *     Winner: (A6,  ,C4)/T=19 
 *     --> Conflicts with local version
 *     --> Local must merge local version (A3,B5,C4) in (A6,  ,C4)
 *     --> Local result is then (A6,B6,C4)	         
 *     
 * CONFLICT 5 at A: 
 *  - Local:     (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,  ,C4)/T=05
 *               (A4,  ,C4)/T=11 (first conflict A)
 *               (A5,  ,C4)/T=12
 *               (A6,  ,C4)/T=19 (last A)
 *  - db-b-4:    (A3,B2,C4)/T=16 (first conflict B)
 *               (A3,B3,C4)/T=17
 *               (A3,B4,C4)/T=18
 *  - db-b-5:    (A3,B5,C4)/T=20 (last B)
 *  - db-c-5:    (A3,  ,C5)/T=13 (first conflict C)
 *  - db-c-7:    (A3,  ,C6)/T=14
 *               (A3,  ,C7)/T=15
 *  - db-c-8:    (A3,  ,C8)/T=21 (last C)
 *               
 *  - Last versions conflicts:                (A3,B5,C4)/T=20 || (A6,  ,C4)/T=19
 *                                            (A3,B5,C4)/T=20 || (A3,  ,C8)/T=21 
 *                                            (A6,  ,C4)/T=19 || (A3,  ,C8)/T=21 
 *  - Last common version between clients:    (empty)
 *  - First conflicting version per client:   (A4,  ,C4)/T=11 (first conflicting A)
 *                                            (A3,B2,C4)/T=16 (first conflicting B)
 *                                            (A3,  ,C5)/T=13 (first conflicting C)
 *  - Winner of first conflicting versions:   (A4,  ,C4)/T=11
 *  - Winning clients histories:              A               
 *                                            (A4,  ,C4)/T=11 
 *                                            (A5,  ,C4)/T=12 
 *                                            (A6,  ,C4)/T=19
 *  - Conflicts in winning histories:         (empty)
 *  - Winning histories lengths               (not relevant)
 *  - Follow this history (ultimate winner):  A 
 *                                            
 *  - Result:
 *     Winner: (A6,  ,C4)/T=19 
 *     --> That's me. Do nothing.           
 *     
 * CONFLICT 6 at C: 
 *  - Local:     (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,  ,C4)/T=05
 *               (A3,  ,C5)/T=13 (first conflict C)
 *               (A3,  ,C6)/T=14
 *               (A3,  ,C7)/T=15
 *               (A3,  ,C8)/T=21 (last C)
 *  - db-a-5:    (A4,  ,C4)/T=11 (first conflict A)
 *               (A5,  ,C4)/T=12
 *  - db-a-6:    (A6,  ,C4)/T=19 (last A)
 *  - db-b-4:    (A3,B2,C4)/T=16 (first conflict B)
 *               (A3,B3,C4)/T=17
 *               (A3,B4,C4)/T=18
 *  - db-b-5:    (A3,B5,C4)/T=20 (last B)
 *               
 *  - Last versions conflicts:                (A3,B5,C4)/T=20 || (A6,  ,C4)/T=19 
 *                                            (A3,B5,C4)/T=20 || (A3,  ,C8)/T=21 
 *                                            (A6,  ,C4)/T=19 || (A3,  ,C8)/T=21 
 *  - Last common version between clients:    (empty)
 *  - First conflicting version per client:   (A4,  ,C4)/T=11 (first conflicting A)
 *                                            (A3,B2,C4)/T=16 (first conflicting B)
 *                                            (A3,  ,C5)/T=13 (first conflicting C)
 *  - Winner of first conflicting versions:   (A4,  ,C4)/T=11
 *  - Winning clients histories:              A               
 *                                            (A4,  ,C4)/T=11 
 *                                            (A5,  ,C4)/T=12 
 *                                            (A6,  ,C4)/T=19
 *  - Conflicts in winning histories:         (empty)
 *  - Winning histories lengths               (not relevant)
 *  - Follow this history (ultimate winner):  A 
 *                                            
 *  - Result:
 *     Winner: (A6,  ,C4)/T=19 
 *     --> Conflicts with local version
 *     --> Local must merge local version (A3,  ,C8) in (A6,  ,C4)
 *     --> Local result is then (A6,  ,C9)	        
 *     
 * CONFLICT 7 at C: 
 *  - Local:     (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,  ,C4)/T=05 
 *               (A3,  ,C5)/T=13 
 *               (A3,  ,C6)/T=14
 *               (A3,  ,C7)/T=15
 *               (A3,  ,C8)/T=21
 *               (A3,  ,C9)/T=22 (last C) 
 *  - db-b-1:    (  ,  ,C1)/T=01
 *               (  ,  ,C2)/T=02
 *               (  ,  ,C3)/T=03
 *               (  ,B1,C3)/T=07 
 *  - db-b-4:    (A3,B2,C4)/T=16 (first conflict B)
 *               (A3,B3,C4)/T=17
 *               (A3,B4,C4)/T=18
 *  - db-b-5:    (A3,B5,C4)/T=20 
 *  - db-b-6:    (A6,B6,C4)/T=23 (last B) 
 *  
 *  
 *  
 *  
 *  
 *               
 *  - Last versions conflicts:                (A6,B5,C4)/T=23 || (A3,  ,C9)/T=22 
 *  - Last common version between clients:    (empty)
 *  - First conflicting version per client:   (A3,  ,C9)/T=22 (first conflicting C)
 *                                            (A6,B6,C4)/T=23 (first conflicting B)
 *  - Winner of first conflicting versions:   (A4,  ,C4)/T=11
 *  - Winning clients histories:              A               
 *                                            (A4,  ,C4)/T=11 
 *                                            (A5,  ,C4)/T=12 
 *                                            (A6,  ,C4)/T=19
 *  - Conflicts in winning histories:         (empty)
 *  - Winning histories lengths               (not relevant)
 *  - Follow this history (ultimate winner):  A 
 *                                            
 *  - Result:
 *     Winner: (A6,  ,C4)/T=19 
 *     --> Conflicts with local version
 *     --> Local must merge local version (A3,  ,C8) in (A6,  ,C4)
 *     --> Local result is then (A6,  ,C9)	        
 */		
public class MixedUpDownScenarioTest {
	@Test
	@Ignore
	public void testMixedScenario1() throws Exception {
		// Setup 
		TransferSettings testConnection = TestConfigUtil.createTestLocalConnection();
		
		TestClient clientA = new TestClient("A", testConnection);
		TestClient clientB = new TestClient("B", testConnection);
		TestClient clientC = new TestClient("C", testConnection);
		
		// Run 
		clientC.createNewFile("C1");
		clientC.up();
		clientC.createNewFile("C2");
		clientC.up();
		clientC.createNewFile("C3");
		clientC.up();
		
		clientB.down(); // NO CONFLICT
		assertFileListEquals("Client B and C should be on the same versions.", clientB.getLocalFilesExcludeLockedAndNoRead(), clientC.getLocalFilesExcludeLockedAndNoRead());		

		clientC.createNewFile("C4"); // up without down! Evil!
		clientC.up();
		
		clientA.down(); // NO CONFLICT
		assertFileListEquals("Client A and C should be on the same versions.", clientA.getLocalFilesExcludeLockedAndNoRead(), clientC.getLocalFilesExcludeLockedAndNoRead());
		assertEquals("Client A should have C4, client B should not", clientA.getLocalFilesExcludeLockedAndNoRead().size()-1, clientB.getLocalFilesExcludeLockedAndNoRead().size());
		
		clientB.createNewFile("B1,C3");
		clientB.up();
		
		clientA.createNewFile("A1,C4");
		clientA.up();
		clientA.createNewFile("A2,C4");
		clientA.up();
		clientA.createNewFile("A3,C4");
		clientA.up();
		
		clientB.down(); // CONFLICT 1
		fail("Add some asserts");
		assertFileListEquals(clientA.getLocalFilesExcludeLockedAndNoRead(), clientB.getLocalFilesExcludeLockedAndNoRead());
		
		clientA.down(); // CONFLICT 2
		clientC.down(); // CONFLICT 3
		assertFileListEquals(clientA.getLocalFilesExcludeLockedAndNoRead(), clientB.getLocalFilesExcludeLockedAndNoRead());
		assertFileListEquals(clientB.getLocalFilesExcludeLockedAndNoRead(), clientC.getLocalFilesExcludeLockedAndNoRead());
		
		clientA.createNewFile("A4,C4");
		clientA.up();
		clientA.createNewFile("A5,C4");
		clientA.up();

		clientC.createNewFile("A3,C5");
		clientC.up();
		clientC.createNewFile("A3,C6");
		clientC.up();
		clientC.createNewFile("A3,C7");
		clientC.up();
		
		clientB.createNewFile("A3,B2,C4");
		clientB.up();				
		clientB.createNewFile("A3,B3,C4");
		clientB.up();		
		clientB.createNewFile("A3,B4,C4");
		clientB.up();	
		
		clientA.createNewFile("A6,C4");
		clientA.up();
		
		clientB.createNewFile("A3,B5,C4");
		clientB.up();	
		
		clientC.createNewFile("A3,C8");
		clientC.up();
				
		clientB.down(); // CONFLICT 4
		clientA.down(); // CONFLICT 5
		clientC.down(); // CONFLICT 6
		
		clientA.up();
		clientA.down();
		
		clientB.up();
		clientB.down();
		
		clientC.up();
		clientC.down();
				
		clientC.up();
		clientB.up();
		
		clientC.down(); // CONFLICT 7
		clientB.down(); // CONFLICT 8
		clientA.down(); // CONFLICT 9
		
		assertFileListEquals(clientA.getLocalFilesExcludeLockedAndNoRead(), clientB.getLocalFilesExcludeLockedAndNoRead());
		assertFileListEquals(clientB.getLocalFilesExcludeLockedAndNoRead(), clientC.getLocalFilesExcludeLockedAndNoRead());
		
		assertEquals("File list count does not match.", 19, clientA.getLocalFilesExcludeLockedAndNoRead().size());
		
		// Tear down
		clientA.deleteTestData();
		clientB.deleteTestData();
		clientC.deleteTestData();
	}
}
