1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use crate::{
    common::Result,
    oned::{one_d_reader, OneDReader},
    Exceptions,
};

/**
 * Superclass of {@link OneDReader} implementations that read barcodes in the RSS family
 * of formats.
 */
pub trait AbstractRSSReaderTrait: OneDReader {
    const MAX_AVG_VARIANCE: f32 = 0.2;
    const MAX_INDIVIDUAL_VARIANCE: f32 = 0.45;

    const MIN_FINDER_PATTERN_RATIO: f32 = 9.5 / 12.0;
    const MAX_FINDER_PATTERN_RATIO: f32 = 12.5 / 14.0;

    fn parseFinderValue(counters: &[u32], finderPatterns: &[[u32; 4]]) -> Result<u32> {
        for (value, pattern) in finderPatterns.iter().enumerate() {
            if one_d_reader::pattern_match_variance(
                counters,
                pattern,
                Self::MAX_INDIVIDUAL_VARIANCE,
            ) < Self::MAX_AVG_VARIANCE
            {
                return Ok(value as u32);
            }
        }
        Err(Exceptions::NOT_FOUND)
    }

    /**
     * @param array values to sum
     * @return sum of values
     * @deprecated call {@link MathUtils#sum(int[])}
     */
    #[deprecated]
    fn count(array: &[u32]) -> u32 {
        array.iter().sum::<u32>()
    }

    fn increment(array: &mut [u32], errors: &[f32]) {
        let mut index = 0;
        let mut biggestError = errors[0];
        for (i, error) in errors.iter().enumerate().take(array.len()).skip(1) {
            if *error > biggestError {
                biggestError = *error;
                index = i;
            }
        }
        array[index] += 1;
    }

    fn decrement(array: &mut [u32], errors: &[f32]) {
        let mut index = 0;
        let mut biggestError = errors[0];
        for (i, error) in errors.iter().enumerate().take(array.len()).skip(1) {
            if *error < biggestError {
                biggestError = *error;
                index = i;
            }
        }
        array[index] -= 1;
    }

    fn isFinderPattern(counters: &[u32]) -> bool {
        let firstTwoSum = counters[0] + counters[1];
        let sum = firstTwoSum + counters[2] + counters[3];
        let ratio: f32 = (firstTwoSum as f32) / (sum as f32);
        if ratio >= Self::MIN_FINDER_PATTERN_RATIO && ratio <= Self::MAX_FINDER_PATTERN_RATIO {
            // passes ratio test in spec, but see if the counts are unreasonable
            // let minCounter = counters.iter().min();
            // let maxCounter = counters.iter().max();
            let mut minCounter = u32::MAX;
            let mut maxCounter = u32::MIN;
            for counter in counters {
                maxCounter = std::cmp::max(*counter, maxCounter);
                minCounter = std::cmp::min(*counter, minCounter);
                // if *counter > maxCounter {
                //     maxCounter = *counter;
                // }
                // if *counter < minCounter {
                //     minCounter = *counter;
                // }
            }
            return maxCounter < 10 * minCounter;
        }
        false
    }
}