1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.functor.example.kata.four;
18  
19  import java.io.InputStream;
20  import java.io.InputStreamReader;
21  import java.io.Reader;
22  
23  import org.apache.commons.functor.BinaryFunction;
24  import org.apache.commons.functor.UnaryFunction;
25  import org.apache.commons.functor.adapter.BinaryFunctionUnaryFunction;
26  import org.apache.commons.functor.core.IsNull;
27  import org.apache.commons.functor.core.LeftIdentity;
28  import org.apache.commons.functor.core.RightIdentity;
29  import org.apache.commons.functor.core.algorithm.FoldLeft;
30  import org.apache.commons.functor.core.comparator.IsLessThan;
31  import org.apache.commons.functor.core.composite.Composite;
32  import org.apache.commons.functor.core.composite.Conditional;
33  import org.apache.commons.functor.core.composite.ConditionalBinaryFunction;
34  import org.apache.commons.functor.example.kata.one.Subtract;
35  import org.apache.commons.functor.example.lines.Lines;
36  import org.apache.commons.functor.generator.FilteredGenerator;
37  
38  /**
39   * The real workhorse of this Kata excercise.
40   *
41   * DataMunger wires together various functors and exposes them
42   * as static utility methhods.
43   * @version $Revision: 1171267 $ $Date: 2011-09-15 22:46:08 +0200 (Thu, 15 Sep 2011) $
44   * @author Rodney Waldhoff
45   */
46  public class DataMunger {
47      /** See {@link #process(Reader,int,int,int)} */
48      public static final Object process(final InputStream file, final int selected, final int col1, final int col2) {
49          return process(new InputStreamReader(file),selected,col1,col2);
50      }
51  
52      /**
53       * Processes each line of the given Reader, returning the <i>selected</i> column for the
54       * line where the absolute difference between the integer value of <i>col1</i> and <i>col2</i>
55       * is least.  Note that lines that don't begin with an Integer are ignored.
56       */
57      public static final Object process(final Reader file, final int selected, final int col1, final int col2) {
58          return NthColumn.instance(selected).evaluate(
59                  new FoldLeft<String>(lesserSpread(col1, col2)).evaluate(new FilteredGenerator<String>(Lines.from(file),
60                      Composite.predicate(IsInteger.instance(),NthColumn.instance(0)))));
61      }
62  
63      /**
64       * A BinaryFunction that will calculate the absolute
65       * difference between col1 and col2 in the given
66       * String arguments, and return the argument
67       * whose difference is smallest.
68       */
69      private static final BinaryFunction<String, String, String> lesserSpread(final int col1, final int col2) {
70          return new ConditionalBinaryFunction<String, String, String>(
71              IsNull.<String>left(),                                 // if left is null
72              RightIdentity.<String, String>function(),                      //   return right
73              Conditional.function(                          //   else return the parameter with the least spread
74                  Composite.predicate(                       //     if left is less than right
75                      IsLessThan.instance(),
76                      absSpread(col1,col2),
77                      absSpread(col1,col2)),
78                  LeftIdentity.<String, String>function(),                   //       return left
79                  RightIdentity.<String, String>function()                   //       else return right
80              )
81          );
82      }
83  
84      /**
85       * A UnaryFunction that returns the absolute value of the difference
86       * between the Integers stored in the <i>col1</i> and <i>col2</i>th
87       * whitespace delimited columns of the input line (a String).
88       */
89      private static UnaryFunction<String, Integer> absSpread(final int col1, final int col2) {
90          return Composite.function(
91              Abs.instance(),
92              new BinaryFunctionUnaryFunction<String, Number>(
93                  Composite.function(
94                      Subtract.instance(),
95                      Composite.function(ToInteger.instance(),NthColumn.instance(col1)),
96                      Composite.function(ToInteger.instance(),NthColumn.instance(col2)))
97                  ));
98      }
99  
100 }