001    package sears.file;
002    
003    import java.io.File;
004    import java.util.ArrayList;
005    
006    import sears.file.exception.io.FileConversionException;
007    import sears.gui.MainWindow;
008    import sears.tools.Utils;
009    
010    /**
011     * Provides access method to file like <i>open</i> and <i>save</i>
012     * <br>An instance of this class captures error coming from the conversion of file to subtitle file
013     */
014    public class FileSystemAccess {
015    
016            private static FileSystemAccess instance;
017            private MainWindow mainWindow;
018    
019            /** (<tt>int</tt>) maximum authorized size for a subtitle file, 2 Mo */
020            public final static int MAX_SUBTITLE_FILE_SIZE = 2000000;
021    
022            /**
023             * Gives the same instance of this class
024             * <br>Only used by <tt>MainWindow</tt> class
025             * @return      an object instance of <tt>FileSystemAccess</tt> class.
026             */
027            public static FileSystemAccess getInstance() {
028                    if( instance == null ) {
029                            instance = new FileSystemAccess(MainWindow.instance);
030                    }
031                    return instance;
032            }
033    
034            /**
035             * Default constructor
036             * @param mainWindow    the extended controller
037             */
038            protected FileSystemAccess(MainWindow mainWindow) {
039                    if( mainWindow == null ) {
040                            throw new NullPointerException("main window cannot be null");
041                    }
042                    this.mainWindow = mainWindow;
043            }
044    
045            /**
046             * Tests the length of the <tt>java.io.File</tt> given in parameters
047             * @param file                                          the file to test
048             * @throws FileConversionException      if length or access to the file cause a problem 
049             * @throws NullPointerException         if <tt>file</tt> is null
050             */
051            private void ensureFileLengthCoherence(File file) throws FileConversionException {
052                    try {
053                            if( file.length() >= MAX_SUBTITLE_FILE_SIZE ) {
054                                    throw FileConversionException.getAccessException(
055                                                    FileConversionException.UNSUPPORTED_FILE_SIZE, file);
056                            }
057                    } catch( SecurityException e) {
058                            throw FileConversionException.getAccessException(
059                                            FileConversionException.READ_ACCESS, file);
060                    }
061            }
062            
063            /**
064             * Provides a way to get a <tt>SubtitleFile</tt> instance from a file
065             * @param file          the file to convert
066             * @param charset       the charset used for the conversion
067             * @return                      the <tt>SubtitleFile</tt> object created or null if an error occurs
068             */
069            public SubtitleFile openFile(File file, String charset) {
070                    return openFile(file, null, charset);
071            }
072            
073            private void fillArray(ArrayList<Subtitle> listToFill, ArrayList<Subtitle> savedList) {
074                    listToFill.clear();
075                    listToFill.addAll(savedList);
076            }
077    
078            /**
079             * Provides a way to get <tt>SubtitleFile</tt> instance from a file
080             * <br>If an error occurs an error dialog is called
081             * @param file                  the file to convert
082             * @param subtitleList  the subtitle list to fill
083             * @param charset               the charset used for the conversion
084             * @return                              the <tt>SubtitleFile</tt> object created or null if an error occurs
085             */
086            public SubtitleFile openFile(File file, ArrayList<Subtitle> subtitleList, String charset) {
087                    SubtitleFile subtitleFile = null;
088                    // save the subtitle list in case of error:
089                    ArrayList<Subtitle> savedSubtitleList = new ArrayList<Subtitle>();
090                    if( subtitleList == null ) {
091                            // subtitleList becomes an empty array
092                            subtitleList = savedSubtitleList;
093                    } else {                        
094                            savedSubtitleList.addAll(subtitleList);
095                            subtitleList.clear();
096                    }
097                    // Try to create the new subtitleFile:
098                    try {   
099                            // ensure that the file length is not bigger than the one supported by Sears
100                            ensureFileLengthCoherence(file);
101                            // try to create a new Subtitle file
102                            subtitleFile = SubtitleFile.getInstance(file, subtitleList, charset);
103                    } catch ( FileConversionException e ) {
104                            //
105                            // file conversion error occurs:
106                            // - malformed subtitle file
107                            // - read access error
108                            
109                            // return saved list
110                            fillArray(subtitleList, savedSubtitleList);
111                            charset = mainWindow.showOpenErrorDialog(e.getMessage(), e.getDetail(), e.couldBeABadEncoding());
112                            if( charset != null ) {
113                                    mainWindow.openFile(file, charset);
114                            } // else, error dialog has be closed by user, do not try to reopen file
115                    } catch ( NullPointerException e) {
116                            //
117                            // DEVELOPER:
118                            // one of the parameters is null !!
119                            
120                            // return saved list
121                            fillArray(subtitleList, savedSubtitleList);
122                            e.printStackTrace();
123                            mainWindow.showOpenErrorDialog("unknow error", e.toString(), false);
124                            
125                    } catch ( Exception e ) {
126                            //
127                            // DEVELOPER:
128                            // if an unknown error occurs, a generic dialog is show...
129                            
130                            // return saved list
131                            fillArray(subtitleList, savedSubtitleList);
132                            e.printStackTrace();
133                            mainWindow.showOpenErrorDialog("unknow error",e.toString(), false);                     
134                    }
135                    return subtitleFile;
136            }
137    
138            /**
139             * Writes the subtitle to a file and invokes an error dialog if an error occurs during the action
140             * @param file                  the file in which the subtitle must be write
141             * @param subtitleFile  the subtitle to write
142             * @param charset               the charset used to write the file, if null the subtitle's charset will be used
143             * @return                              true if action succeed, false if not
144             */
145            public boolean saveFile(File file, SubtitleFile subtitleFile, String charset) {
146                    boolean isFileSaved = false;
147                    if (subtitleFile != null) {
148                            if( charset != null ) {
149                                    subtitleFile.setCharset(charset);
150                            } // else the file will be saved with this defined charset
151                            try {
152                                    //we have to check wether we are saving into the same format
153                                    if(subtitleFile.getFile().getName().endsWith(Utils.getExtension(file))){
154                                            //If same extension, save the file
155                                            subtitleFile.writeToFile(file);
156                                    }else{
157                                            //If not the same extension, create the new subtitle file., using the empty constructor of getInstance facility (true)
158                                            SubtitleFile newFile = SubtitleFile.getInstance(file, null, null, true);
159                                            //File has not been set by empty constructor, set it
160                                            newFile.setFile(file);
161                                            //copy subtitle list
162                                            newFile.setSubtitleList(subtitleFile.getSubtitleList());
163                                            //And save the new file
164                                            newFile.writeToFile(file);
165                                    }
166                                    isFileSaved = true;
167                            } catch (FileConversionException e) {
168                                    mainWindow.showSaveErrorDialog(e.getMessage(), e.getDetail());
169                            } catch (Exception e) {
170                                    mainWindow.showSaveErrorDialog(e.getMessage(),e.getLocalizedMessage());
171                            }
172                    }               
173                    return isFileSaved;
174            }
175    }