| // Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | import 'package:status_file/src/expression.dart'; | 
 | import 'package:status_file/status_file_entries_file_checker.dart'; | 
 |  | 
 | import 'canonical_status_file.dart'; | 
 | import 'dart:convert'; | 
 |  | 
 | StatusFile normalizeStatusFile(StatusFile statusFile, | 
 |     {required bool deleteNonExisting}) { | 
 |   StatusFile newStatusFile = _sortSectionsAndCombine(statusFile); | 
 |   for (var section in newStatusFile.sections) { | 
 |     if (deleteNonExisting) { | 
 |       _deleteNonExistingEntries(statusFile, section); | 
 |     } | 
 |     _sortEntriesInSection(section); | 
 |     _oneLineBetweenSections(section); | 
 |   } | 
 |  | 
 |   // Remove any empty sections. | 
 |   newStatusFile.sections.removeWhere((section) => | 
 |       section.sectionHeaderComments.isEmpty && | 
 |       (section.entries.isEmpty || | 
 |           (section.entries.length == 1 && | 
 |               section.entries.single is EmptyEntry))); | 
 |  | 
 |   // Remove empty line at the end of the file | 
 |   newStatusFile.sections.last.entries.removeLast(); | 
 |   return newStatusFile; | 
 | } | 
 |  | 
 | void _deleteNonExistingEntries(StatusFile file, StatusSection section) { | 
 |   Uri statusFileUri = Uri.base.resolveUri(Uri.file(file.path)); | 
 |   Set<Entry> remove = {}; | 
 |   for (var entry in section.entries.whereType<StatusEntry>()) { | 
 |     if (isNonExistingEntry(statusFileUri, entry)) { | 
 |       // Doesn't exist. Remove it. | 
 |       remove.add(entry); | 
 |     } | 
 |   } | 
 |   if (remove.isNotEmpty) { | 
 |     section.entries.removeWhere(remove.contains); | 
 |   } | 
 | } | 
 |  | 
 | /// Sort section entries alphabetically. | 
 | void _sortEntriesInSection(StatusSection section) { | 
 |   section.entries.sort((a, b) { | 
 |     if (a is CommentEntry) { | 
 |       return -1; | 
 |     } | 
 |     if (b is CommentEntry) { | 
 |       return 1; | 
 |     } | 
 |     if (a is StatusEntry && b is StatusEntry) { | 
 |       return a.path.compareTo(b.path); | 
 |     } | 
 |     if (a is StatusEntry) { | 
 |       return -1; | 
 |     } | 
 |     if (b is StatusEntry) { | 
 |       return 1; | 
 |     } | 
 |     return 0; | 
 |   }); | 
 | } | 
 |  | 
 | /// Ensure that there is only one empty line to end a section. | 
 | void _oneLineBetweenSections(StatusSection section) { | 
 |   section.entries.removeWhere((entry) => entry is EmptyEntry); | 
 |   section.entries | 
 |       .add(EmptyEntry(section.lineNumber + section.entries.length + 1)); | 
 | } | 
 |  | 
 | StatusFile _sortSectionsAndCombine(StatusFile statusFile) { | 
 |   // Create the new status file to be returned. | 
 |   StatusFile oldStatusFile = StatusFile.parse( | 
 |       statusFile.path, LineSplitter.split(statusFile.toString()).toList()); | 
 |   List<StatusSection> newSections = []; | 
 |   // Copy over all sections and normalize all the expressions. | 
 |   for (var section in oldStatusFile.sections) { | 
 |     if (section.condition != Expression.always) { | 
 |       if (section.isEmpty()) continue; | 
 |  | 
 |       newSections.add(StatusSection(section.condition.normalize(), | 
 |           section.lineNumber, section.sectionHeaderComments) | 
 |         ..entries.addAll(section.entries)); | 
 |     } else { | 
 |       newSections.add(section); | 
 |     } | 
 |   } | 
 |  | 
 |   // Sort the headers | 
 |   newSections.sort((a, b) => a.condition.compareTo(b.condition)); | 
 |  | 
 |   // See if we can combine section headers by simple comparison. | 
 |   var newStatusFile = StatusFile(statusFile.path); | 
 |   newStatusFile.sections.add(newSections[0]); | 
 |   for (var i = 1; i < newSections.length; i++) { | 
 |     var previousSection = newSections[i - 1]; | 
 |     var currentSection = newSections[i]; | 
 |     if (previousSection.condition.compareTo(currentSection.condition) == 0) { | 
 |       newStatusFile.sections.last.entries.addAll(currentSection.entries); | 
 |     } else { | 
 |       newStatusFile.sections.add(currentSection); | 
 |     } | 
 |   } | 
 |   return newStatusFile; | 
 | } |