/*******************************************************************************
* Breakout Cave Survey Visualizer
*
* Copyright (C) 2014 James Edwards
*
* jedwards8 at fastmail dot fm
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*******************************************************************************/
package org.breakout.tools;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.andork.collect.LineIterable;
import org.andork.collect.LinkedHashSetMultiMap;
import org.andork.collect.MultiMap;
import org.andork.util.Java7.Objects;
import org.andork.util.StringUtils;
public class ScannedNotesMerger
{
public static void main( String[ ] args ) throws Exception
{
File statFile = new File( "C:\\Users\\Andy\\Documents\\FRCS\\Data\\STAT.txt" );
File surveyFile = new File( "C:\\Users\\Andy\\Documents\\FRCS\\Breakout Settings (FRCS Only)\\frcs-survey.txt" );
File notesDir = new File( "C:\\Users\\Andy\\Documents\\FRCS\\Survey Notes" );
List<List<String>> shots = new ArrayList<List<String>>( );
MultiMap<String, List<String>> indexedShots = LinkedHashSetMultiMap.newInstance( );
for( String line : LineIterable.linesOf( surveyFile ) )
{
List<String> split = new ArrayList<String>( Arrays.asList( line.split( "\t" ) ) );
shots.add( split );
String alpha0 = alpha( split.get( 0 ) );
String alpha1 = alpha( split.get( 1 ) );
if( !StringUtils.isNullOrEmpty( alpha0 ) )
{
indexedShots.put( alpha0 , split );
}
if( !StringUtils.isNullOrEmpty( alpha1 ) )
{
indexedShots.put( alpha1 , split );
}
}
Map<Integer, File> notesFiles = new HashMap<>( );
MultiMap<Date, File> datedFiles = LinkedHashSetMultiMap.newInstance( );
Pattern notesNamePattern = Pattern.compile( "FRCS_(\\d+)_((\\d+)-(\\d+)-(\\d+))\\.pdf" );
SimpleDateFormat fileDateFormat = new SimpleDateFormat( "MM-dd-yyyy" );
for( File file : notesDir.listFiles( ) )
{
String name = file.getName( );
Matcher m = notesNamePattern.matcher( name );
if( m.find( ) )
{
notesFiles.put( Integer.parseInt( m.group( 1 ) ) , file );
datedFiles.put( fileDateFormat.parse( m.group( 2 ) ) , file );
}
}
Iterator<String> statIter = LineIterable.linesOf( statFile ).iterator( );
int lineNumber = 0;
int lastHeaderLine = -1;
int tripNumber = -1;
List<StationMatcher> tripMatchers = null;
Date tripDate;
SimpleDateFormat dateFormat = new SimpleDateFormat( "MM/dd/yy" );
Map<Date, Map<Integer, List<StationMatcher>>> stationMatchers = new HashMap<>( );
while( statIter.hasNext( ) )
{
String line = statIter.next( );
if( line.length( ) > 3 && line.substring( 0 , 3 ).matches( "\\s*\\d+" ) )
{
tripNumber = Integer.parseInt( line.substring( 0 , 3 ).trim( ) );
lastHeaderLine = lineNumber;
tripDate = dateFormat.parse( line.substring( 5 , 13 ).replace( ' ' , '0' ) );
tripMatchers = new ArrayList<>( );
Map<Integer, List<StationMatcher>> matchers = stationMatchers.get( tripDate );
if( matchers == null )
{
matchers = new HashMap<>( );
matchers.put( tripNumber , tripMatchers );
stationMatchers.put( tripDate , matchers );
}
}
if( lastHeaderLine >= 0 && lineNumber - lastHeaderLine > 1 )
{
int step = 13;
for( int i = 33 ; i < line.length( ) ; i += step )
{
String part = line.substring( i , i + step ).trim( );
if( !part.isEmpty( ) )
{
tripMatchers.add( new StationMatcher( part ) );
}
}
}
lineNumber++ ;
}
List<String> header = shots.get( 0 );
int dateColumn = -1;
int scannedNotesColumn = -1;
for( int i = 0 ; i < header.size( ) ; i++ )
{
if( "Date".equalsIgnoreCase( header.get( i ) ) )
{
dateColumn = i;
}
if( "Scanned Notes".equalsIgnoreCase( header.get( i ) ) )
{
scannedNotesColumn = i;
}
}
List<String> prevShot = null;
for( List<String> shot : shots )
{
List<String> actualPrevShot = prevShot;
prevShot = shot;
if( shot.size( ) <= dateColumn )
{
continue;
}
Date shotDate = null;
try
{
shotDate = dateFormat.parse( shot.get( dateColumn ) );
}
catch( Exception ex )
{
continue;
}
Map<Integer, List<StationMatcher>> matchers = stationMatchers.get( shotDate );
boolean fromMatched = false;
boolean toMatched = false;
if( matchers != null )
{
for( Map.Entry<Integer, List<StationMatcher>> entry : matchers.entrySet( ) )
{
fromMatched = false;
toMatched = false;
int eTripNumber = entry.getKey( );
File notesFile = notesFiles.get( eTripNumber );
if( notesFile == null )
{
continue;
}
if( matchers.size( ) > 1 )
{
List<StationMatcher> eTripMatchers = entry.getValue( );
for( StationMatcher matcher : eTripMatchers )
{
if( matcher.matches( shot.get( 0 ) ) )
{
fromMatched = true;
break;
}
}
if( !fromMatched )
{
break;
}
for( StationMatcher matcher : eTripMatchers )
{
if( matcher.matches( shot.get( 1 ) ) )
{
toMatched = true;
break;
}
}
if( !toMatched )
{
break;
}
}
else
{
fromMatched = toMatched = true;
}
if( fromMatched && toMatched )
{
while( shot.size( ) <= scannedNotesColumn )
{
shot.add( "" );
}
shot.set( scannedNotesColumn , notesFile.toString( ) );
break;
}
}
}
if( !fromMatched || !toMatched )
{
if( actualPrevShot.size( ) > scannedNotesColumn && shot.get( dateColumn ).equals( actualPrevShot.get( dateColumn ) ) )
{
while( shot.size( ) <= scannedNotesColumn )
{
shot.add( "" );
}
shot.set( scannedNotesColumn , actualPrevShot.get( scannedNotesColumn ) );
}
else if( datedFiles.get( shotDate ).size( ) == 1 )
{
while( shot.size( ) <= scannedNotesColumn )
{
shot.add( "" );
}
shot.set( scannedNotesColumn , datedFiles.getOnlyValue( shotDate ).toString( ) );
}
}
}
FileOutputStream fileOut = new FileOutputStream( new File( surveyFile.getParent( ) , "frcs-new-survey.txt" ) );
PrintStream out = new PrintStream( fileOut );
for( List<String> shot : shots )
{
System.out.println( StringUtils.join( "\t" , shot ) );
out.println( StringUtils.join( "\t" , shot ) );
}
}
private static String alpha( String station )
{
int start;
for( start = 0 ; start < station.length( ) ; start++ )
{
if( Character.isDigit( station.charAt( start ) ) )
{
break;
}
}
return station.substring( 0 , start );
}
private static Integer number( String station )
{
int start, end;
for( start = 0 ; start < station.length( ) ; start++ )
{
if( Character.isDigit( station.charAt( start ) ) )
{
break;
}
}
for( end = start + 1 ; end < station.length( ) ; end++ )
{
if( !Character.isDigit( station.charAt( end ) ) )
{
break;
}
}
if( start < station.length( ) )
{
try
{
return Integer.parseInt( station.substring( start , end ) );
}
catch( Exception ex )
{
ex.printStackTrace( );
}
}
return -1;
}
private static class StationMatcher
{
String alpha;
Integer start;
Integer end;
Pattern surveyRangePattern = Pattern.compile( "([A-Za-z$]+)(\\d+)-([A-Za-z$]+)(\\d+)" );
Pattern singleSurveyPattern = Pattern.compile( "([A-Za-z$]+)(\\d+)?(\\s+(SIDE|LOOP))?" );
public String toString( )
{
StringBuilder sb = new StringBuilder( );
if( alpha != null )
{
sb.append( alpha );
}
if( start != null )
{
sb.append( start );
if( end != null && !end.equals( start ) )
{
sb.append( '-' ).append( alpha ).append( end );
}
}
return sb.toString( );
}
private StationMatcher( String s )
{
Matcher m;
m = surveyRangePattern.matcher( s );
if( m.find( ) )
{
alpha = m.group( 1 );
start = Integer.parseInt( m.group( 2 ) );
end = Integer.parseInt( m.group( 4 ) );
if( end < start )
{
int temp = start;
start = end;
end = temp;
}
}
else
{
m = singleSurveyPattern.matcher( s );
if( m.find( ) )
{
alpha = m.group( 1 );
if( m.group( 2 ) != null )
{
start = end = Integer.parseInt( m.group( 2 ) );
}
}
}
}
public boolean matches( String station )
{
String salpha = alpha( station );
Integer snumber = number( station );
if( !Objects.equals( alpha , salpha ) )
{
return false;
}
if( start != null && snumber != null && snumber < start )
{
return false;
}
if( end != null && snumber != null && snumber > end )
{
return false;
}
return true;
}
}
}