| 1 | /* |
| 2 | Copyright - 2017 2023 - wwwouaiebe - Contact: https://www.ouaie.be/ |
| 3 | |
| 4 | This program is free software; |
| 5 | you can redistribute it and/or modify it under the terms of the |
| 6 | GNU General Public License as published by the Free Software Foundation; |
| 7 | either version 3 of the License, or any later version. |
| 8 | |
| 9 | This program is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License |
| 15 | along with this program; if not, write to the Free Software |
| 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | */ |
| 18 | /* |
| 19 | Changes: |
| 20 | - v4.0.0: |
| 21 | - created from v3.6.0 |
| 22 | Doc reviewed 202208 |
| 23 | */ |
| 24 | |
| 25 | import DictionaryItem from './DictionaryItem.js'; |
| 26 | import { NOT_FOUND, ZERO, ONE } from '../../main/Constants.js'; |
| 27 | |
| 28 | /* ------------------------------------------------------------------------------------------------------------------------- */ |
| 29 | /** |
| 30 | This class contains the OsmSearch dictionary and methods to perform changes in the dictionary |
| 31 | |
| 32 | See DictionaryItem for dictionary items |
| 33 | |
| 34 | See theOsmSearchDictionary for the one and only one instance of this class |
| 35 | */ |
| 36 | /* ------------------------------------------------------------------------------------------------------------------------- */ |
| 37 | |
| 38 | class OsmSearchDictionary { |
| 39 | |
| 40 | /** |
| 41 | the root item of the dictionary |
| 42 | @type {DictionaryItem} |
| 43 | */ |
| 44 | |
| 45 | #dictionary; |
| 46 | |
| 47 | /** |
| 48 | A map with the all the DictionaryItem created, selectable by their objId |
| 49 | @type {Map} |
| 50 | */ |
| 51 | |
| 52 | #itemsMap; |
| 53 | |
| 54 | /** |
| 55 | the currentItem treated by the #parseLine method |
| 56 | @type {DictionaryItem} |
| 57 | */ |
| 58 | |
| 59 | #currentItem; |
| 60 | |
| 61 | /** |
| 62 | Array used to store a reference to the items property of the DictionaryItem Objects |
| 63 | and so build the tree. |
| 64 | @type {Array.<Array.<DictionaryItem>>} |
| 65 | */ |
| 66 | |
| 67 | #itemsArray; |
| 68 | |
| 69 | /** |
| 70 | Split a line from the csv file into cells and add a DictionaryItem or a filterTag to the dictionary |
| 71 | @param {String} line A line of the csv file that will be parsed |
| 72 | */ |
| 73 | |
| 74 | #parseLine ( line ) { |
| 75 | |
| 76 | // split the linres into cells |
| 77 | const cells = line.split ( ';' ); |
| 78 | |
| 79 | // removing empty cells at the end of the line |
| 80 | while ( '' === cells [ cells.length - ONE ] ) { |
| 81 | cells.pop ( ); |
| 82 | } |
| 83 | |
| 84 | // The cell position in line. Used to build the tree |
| 85 | let cellPos = ZERO; |
| 86 | |
| 87 | // An array with filterTags objects used to filter the osm elements. See DictionaryItem |
| 88 | const filterTags = []; |
| 89 | cells.forEach ( |
| 90 | cell => { |
| 91 | if ( '' !== cell ) { |
| 92 | |
| 93 | // The cell contains something |
| 94 | if ( NOT_FOUND === cell.indexOf ( '=' ) ) { |
| 95 | |
| 96 | // The cell don't contains the = char. A new DictionaryItem is created |
| 97 | this.#currentItem = new DictionaryItem ( cell ); |
| 98 | |
| 99 | // The item is added to the itemsMap |
| 100 | this.#itemsMap.set ( this.#currentItem.objId, this.#currentItem ); |
| 101 | |
| 102 | this.#itemsArray [ cellPos ].push ( this.#currentItem ); |
| 103 | this.#itemsArray [ cellPos + ONE ] = this.#currentItem.items; |
| 104 | } |
| 105 | else { |
| 106 | |
| 107 | // Each cell is splited into a key and a value |
| 108 | let keyAndValue = cell.split ( '=' ); |
| 109 | |
| 110 | if ( 'element' === keyAndValue [ ZERO ] ) { |
| 111 | |
| 112 | // Only one elementType is acceptable for this item |
| 113 | this.#currentItem.setElementType ( keyAndValue [ ONE ] ); |
| 114 | } |
| 115 | else { |
| 116 | |
| 117 | // A filterTag object is created... |
| 118 | let filterTag = {}; |
| 119 | |
| 120 | // ...and a property added to the object. The property name is the key found in the cell |
| 121 | // and the property value is the value found in the cell, except when the value is * |
| 122 | filterTag [ keyAndValue [ ZERO ] ] = |
| 123 | '*' === keyAndValue [ ONE ] ? null : keyAndValue [ ONE ]; |
| 124 | |
| 125 | // ...and the filterTag object pushed in the array |
| 126 | filterTags.push ( filterTag ); |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | cellPos ++; |
| 131 | } |
| 132 | ); |
| 133 | if ( ZERO !== filterTags.length ) { |
| 134 | this.#currentItem.filterTagsArray.push ( filterTags ); |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | /** |
| 139 | Mark as expanded an item and all the childrens |
| 140 | @param {DictionaryItem} item The item to mark as expanded |
| 141 | */ |
| 142 | |
| 143 | #expand ( item ) { |
| 144 | item.items.forEach ( |
| 145 | subItem => { this.#expand ( subItem ); } |
| 146 | ); |
| 147 | item.isExpanded = true; |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | Mark as not expanded an item and all the childrens |
| 152 | @param {DictionaryItem} item The item to mark as not expanded |
| 153 | */ |
| 154 | |
| 155 | #collapse ( item ) { |
| 156 | item.items.forEach ( |
| 157 | subItem => { this.#collapse ( subItem ); } |
| 158 | ); |
| 159 | item.isExpanded = false; |
| 160 | } |
| 161 | |
| 162 | /** |
| 163 | The constructor |
| 164 | */ |
| 165 | |
| 166 | constructor ( ) { |
| 167 | this.#dictionary = new DictionaryItem ( '', true ); |
| 168 | this.#itemsMap = new Map ( ); |
| 169 | this.#itemsMap.set ( this.#dictionary.objId, this.#dictionary ); |
| 170 | this.#itemsArray = [ this.#dictionary.items ]; |
| 171 | Object.freeze ( this ); |
| 172 | } |
| 173 | |
| 174 | /** |
| 175 | The dictionary |
| 176 | @type {DictionaryItem} |
| 177 | */ |
| 178 | |
| 179 | get dictionary ( ) { return this.#dictionary; } |
| 180 | |
| 181 | /** |
| 182 | Parse the content of the TravelNotesSearchDictionaryXX.csv and build a tree of DictionaryItem |
| 183 | with this content |
| 184 | @param {String} dictionaryTextContent The content of the TravelNotesSearchDictionaryXX.csv file |
| 185 | */ |
| 186 | |
| 187 | parseDictionary ( dictionaryTextContent ) { |
| 188 | |
| 189 | // split the dictionary content into lines and analyse each line |
| 190 | dictionaryTextContent.split ( /\r\n|\r|\n/ ).forEach ( |
| 191 | line => { |
| 192 | if ( '' !== line ) { |
| 193 | this.#parseLine ( line ); |
| 194 | } |
| 195 | } |
| 196 | ); |
| 197 | } |
| 198 | |
| 199 | /** |
| 200 | Mark as selected/not selected an item identified by it's objId and all the chidrens of this item |
| 201 | @param {Number} itemObjId The objId of the item |
| 202 | @param {Boolean} isSelected The value to set for isSelected |
| 203 | */ |
| 204 | |
| 205 | selectItem ( itemObjId, isSelected ) { |
| 206 | this.#itemsMap.get ( itemObjId ).isSelected = isSelected; |
| 207 | } |
| 208 | |
| 209 | /** |
| 210 | Mark the complete dictionary as not selected |
| 211 | */ |
| 212 | |
| 213 | unselectAll ( ) { |
| 214 | this.#dictionary.isSelected = false; |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | Mark as expanded an item identified by it's objId |
| 219 | @param {Number} itemObjId The objId of the item |
| 220 | */ |
| 221 | |
| 222 | expandItem ( itemObjId ) { |
| 223 | let item = this.#itemsMap.get ( itemObjId ); |
| 224 | item.isExpanded = ! item.isExpanded; |
| 225 | } |
| 226 | |
| 227 | /** |
| 228 | Mark the complete dictionary as expanded |
| 229 | */ |
| 230 | |
| 231 | expand ( ) { |
| 232 | this.#expand ( this.#dictionary ); |
| 233 | } |
| 234 | |
| 235 | /** |
| 236 | Mark the complete dictionary except the root item as not expanded |
| 237 | */ |
| 238 | |
| 239 | collapse ( ) { |
| 240 | this.#dictionary.items.forEach ( |
| 241 | item => this.#collapse ( item ) |
| 242 | ); |
| 243 | } |
| 244 | |
| 245 | } |
| 246 | |
| 247 | /* ------------------------------------------------------------------------------------------------------------------------- */ |
| 248 | /** |
| 249 | The one and only one instance of OsmSearchDictionary class |
| 250 | @type {OsmSearchDictionary} |
| 251 | */ |
| 252 | /* ------------------------------------------------------------------------------------------------------------------------- */ |
| 253 | |
| 254 | const theOsmSearchDictionary = new OsmSearchDictionary ( ); |
| 255 | |
| 256 | export default theOsmSearchDictionary; |
| 257 | |
| 258 | /* --- End of file --------------------------------------------------------------------------------------------------------- */ |
| 259 |