Package tvbrowserdataservice.file

Source Code of tvbrowserdataservice.file.DayProgramFile

/*
* TV-Browser
* Copyright (C) 04-2003 Martin Oberhauser (darras@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* CVS information:
*  $RCSfile$
*   $Source$
*     $Date: 2010-06-28 19:33:48 +0200 (Mon, 28 Jun 2010) $
*   $Author: bananeweizen $
* $Revision: 6662 $
*/
package tvbrowserdataservice.file;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.zip.GZIPOutputStream;

import util.exc.TvBrowserException;
import util.io.DownloadJob;
import util.io.FileFormatException;
import util.io.IOUtilities;
import devplugin.Date;

/**
* @author Til Schneider, www.murfman.de
*/
public class DayProgramFile extends AbstractFile {

  private transient devplugin.Channel mChannel;
  private transient devplugin.Date mDate;

  /** The localizer for this class. */
  private static final util.ui.Localizer mLocalizer
    = util.ui.Localizer.getLocalizerFor(DayProgramFile.class);

  private static final TvDataLevel[] LEVEL_ARR = new TvDataLevel[] {
    new TvDataLevel("base", mLocalizer.msg("basicTVListings","Basic TV listings"),true),
    new TvDataLevel("more00-16",mLocalizer.msg("more00-16","")),
    new TvDataLevel("more16-00",mLocalizer.msg("more16-00","")),
    new TvDataLevel("picture00-16", mLocalizer.msg("picture00-16","")),
    new TvDataLevel("picture16-00", mLocalizer.msg("picture16-00","")),
  };

  private static final int FILE_VERSION = 1;

  private static final int ADDITIONAL_FILE_VERSION = 1;

  private int mVersion;

  private ArrayList<ProgramFrame> mProgramFrameList;



  public DayProgramFile() {
    mVersion = 1;
    mProgramFrameList = new ArrayList<ProgramFrame>();
  }

  public DayProgramFile(devplugin.Date date, devplugin.Channel channel) {
    this();
    mDate=date;
    mChannel=channel;
  }


  public devplugin.Date getDate() {
    return mDate;
  }

  public devplugin.Channel getChannel() {
    return mChannel;
  }

  public int getVersion() {
    return mVersion;
  }



  /**
   * @param version
   */
  public void setVersion(int version) {
    mVersion = version;
  }



  public int getProgramFrameCount() {
    return mProgramFrameList.size();
  }



  public ProgramFrame getProgramFrameAt(int index) {
    return mProgramFrameList.get(index);
  }



  public void removeProgramFrameAt(int index) {
    mProgramFrameList.remove(index);
  }



  public void removeAllProgramFrames() {
    mProgramFrameList.clear();
  }



  public void addProgramFrame(ProgramFrame frame) {
    mProgramFrameList.add(frame);
  }



  public int getProgramFrameIndexForId(int id) {
    for (int i = 0; i < getProgramFrameCount(); i++) {
      if (getProgramFrameAt(i).getId() == id) {
        return i;
      }
    }

    // Nothing found
    return -1;
  }



  /**
   * Updates this complete file with an update file.
   *
   * @param updateFile The update to use to patch this day program file.
   * @throws FileFormatException If the update file does not have a higher
   *         version as this file.
   *
   * @see #updateUpdateFile(DayProgramFile)
   * @see #merge(DayProgramFile)
   */
  public void updateCompleteFile(DayProgramFile updateFile)
    throws FileFormatException
  {
    // Go through all frames in the update file
    merge(updateFile, false, true);
  }



  /**
   * Updates this update file with an update file.
   *
   * @param updateFile The update to use to patch this day program file.
   * @throws FileFormatException If the update file does not have a higher
   *         version as this file.
   *
   * @see #updateCompleteFile(DayProgramFile)
   * @see #merge(DayProgramFile)
   */
  public void updateUpdateFile(DayProgramFile updateFile)
    throws FileFormatException
  {
    // Go through all frames in the update file
    merge(updateFile, true, true);
  }



  /**
   * Merges the day program file with a day program file of another level.
   *
   * @param otherProg The day program file to merge with this file.
   * @throws FileFormatException If merging failed.
   *
   * @see #updateCompleteFile(DayProgramFile)
   * @see #updateUpdateFile(DayProgramFile)
   */
  public void merge(DayProgramFile otherProg) throws FileFormatException {
    merge(otherProg, false, false);
  }



  /**
   * Merges two day program files.
   *
   * @param otherFile The day program file to merge with this one.
   * @param thisIsUpdateFile Specifies whether this is an update file.
   *        When an update file is updated for each empty frame in the other
   *        file a empty frame in this frame is created.
   *        When a complete file is updated for each empty frame in the other
   *        file the frame in this file is deleted.
   * @param otherIsUpdateFile Specifies whether the other file is an update
   *        file.
   *        If this file is updated, an empty frame in the other file causes a
   *        deletion of the frame (or the creation of an empty frame).
   *        If this file is merged with another complete file, an empty frame in
   *        the other file is ignored.
   * @throws FileFormatException If the version of the update file is not higher
   *         than the version of this file
   */
  private void merge(DayProgramFile otherFile, boolean thisIsUpdateFile,
    boolean otherIsUpdateFile)
    throws FileFormatException
  {
    // Check the version
    if (otherIsUpdateFile && (otherFile.getVersion() <= getVersion())) {
      throw new FileFormatException("Update file must have a higher version ("
        + otherFile.getVersion() + " <= " + getVersion() + ")");
    }

    // Go through all frames in the merge the day programs
    for (int frameNr = 0; frameNr < otherFile.getProgramFrameCount(); frameNr++) {
      ProgramFrame frame = otherFile.getProgramFrameAt(frameNr);

      // Check whether this frame is obsolete
      // This is the case when the frame is empty (= has no fields)
      if (frame.getProgramFieldCount() == 0) {
        // Check whether this is an complete or an update file
        if (thisIsUpdateFile) {
          // The new update file says that this frame is obsolete
          // -> Add an empty frame to this update file, too

          // Remove an existing frame first
          int index = getProgramFrameIndexForId(frame.getId());
          if (index != -1) {
            removeProgramFrameAt(index);
          }

          // Add the empty frame (to mark the frame as obsolete)
          addProgramFrame(new ProgramFrame(frame.getId()));
        } else {
          if (otherIsUpdateFile) {
            int index = getProgramFrameIndexForId(frame.getId());
            if (index != -1) {
              // The update says, that this frame is obsolete -> delete it
              removeProgramFrameAt(index);
            }
          } else {
            // The other file is a complete file too (maybe from another level)
            // -> Ignore empty frames
          }
        }
      } else {
        // Insert or update the frame

        // Check whether we already have such a frame
        int index = getProgramFrameIndexForId(frame.getId());
        ProgramFrame targetFrame;
        if (index == -1) {
          // This is an insert
          targetFrame = new ProgramFrame(frame.getId());
          addProgramFrame(targetFrame);
        } else {
          // This is an update
          targetFrame = getProgramFrameAt(index);
        }

        // Replace all fields the update file provides
        for (int i = 0; i < frame.getProgramFieldCount(); i++) {
          ProgramField field = frame.getProgramFieldAt(i);

          // Remove the old field, if present
          int fieldIdx = targetFrame.getProgramFieldIndexForTypeId(field.getTypeId());
          if (fieldIdx != -1) {
            targetFrame.removeProgramFieldAt(fieldIdx);
          }

          // Check whether to update or delete the field
          if (field.getBinaryData() == null && !thisIsUpdateFile) {
            // This field should be deleted -> Ignore if this is no update file
          } else {
            /* This field should be updated or deleted in an update file ->
             * Add a copy of the field
             */
            ProgramField copy = (ProgramField) field.clone();
            targetFrame.addProgramField(copy);
          }
        }

        /* If the frame now is empty we have to remove it to prevent
         * it is misinterpreted as a to deleting program frame */
        if(frame.getProgramFieldCount() == 0) {
          index = getProgramFrameIndexForId(frame.getId());

          if(index != -1) {
            removeProgramFrameAt(index);
          }
        }
      }
    }

    if (otherIsUpdateFile) {
      // Upgrade to the new version
      setVersion(otherFile.getVersion());
    }
  }



  public void checkFormat() throws FileFormatException {
    // Check whether there are duplicate program IDs
    for (int i = 0; i < getProgramFrameCount(); i++) {
      ProgramFrame frame = getProgramFrameAt(i);
      // Check whether there is a program that has the same ID than this one
      for (int j = i + 1; j < getProgramFrameCount(); j++) {
        ProgramFrame cmp = getProgramFrameAt(j);

        if (frame.getId() == cmp.getId()) {
          throw new FileFormatException("Program #" + i + " and program #" + j
            + " have the same ID: " + frame.getId());
        }
      }
    }
  }



  /**
   * Reads only the version from a stream.
   *
   * @param stream The stream to read from
   * @return The version of the file
   * @throws IOException If reading failed
   * @throws FileFormatException If the file has a unknown file version
   */
  public static int readVersionFromStream(InputStream stream)
    throws IOException, FileFormatException
  {
    InputStream gIn = IOUtilities.openSaveGZipInputStream(stream);

    int fileVersion = gIn.read();
    if (fileVersion > FILE_VERSION) {
      throw new FileFormatException("Unknown file version: " + fileVersion);
    }

    int version = gIn.read();

    gIn.close();

    return version;
  }



  public static int readVersionFromFile(File file)
    throws IOException, FileFormatException
  {
    BufferedInputStream stream = null;
    try {
      stream = new BufferedInputStream(new FileInputStream(file), 0x4000);

      return readVersionFromStream(stream);
    }
    finally {
      if (stream != null) {
        try { stream.close(); } catch (IOException exc) {}
      }
    }
  }



  public void readFromStream(InputStream stream, DownloadJob job)
    throws IOException, FileFormatException
  {
    InputStream gIn = IOUtilities.openSaveGZipInputStream(stream);

    int fileVersion = gIn.read();
    if (fileVersion > FILE_VERSION) {
      throw new FileFormatException("Unknown file version: " + fileVersion);
    }

    mVersion = gIn.read();

    int programCount = gIn.read();

    if(programCount == 254) {
      try {
        if(job.getServerUrl() != null) {
          String url = job.getServerUrl() + (job.getServerUrl().endsWith("/") ? "" : "/") + getAdditionalFileName(job.getFileName());
          programCount = readProgCountFromStream(IOUtilities.getStream(new URL(url)));
        } else {
          programCount = readProgCountFromStream(new BufferedInputStream(new FileInputStream(getAdditionalFileName(job.getFileName())), 0x4000));
        }
      }catch(Exception e) {}
    }

    mProgramFrameList.clear();
    mProgramFrameList.ensureCapacity(programCount);
    for (int i = 0; i < programCount; i++) {
      ProgramFrame frame = new ProgramFrame();
      frame.readFromStream(gIn);
      mProgramFrameList.add(frame);
    }

    gIn.close();
  }

  private int readProgCountFromStream(InputStream stream) throws IOException, FileFormatException {
    InputStream gIn = IOUtilities.openSaveGZipInputStream(stream);

    gIn.read(); //version

    int count = ((gIn.read() & 0xFF) << 8 ) | (gIn.read() & 0xFF);

    gIn.close();

    return count;
  }

  private void writeProgCountToStream(OutputStream stream) throws IOException, FileFormatException {
    GZIPOutputStream gOut = new GZIPOutputStream(stream);

    gOut.write(ADDITIONAL_FILE_VERSION);

    int count = getProgramFrameCount();

    gOut.write((byte) (count >> 8));
    gOut.write((byte) (count & 0xFF));

    gOut.close();
  }

  public void writeToStream(OutputStream stream, File file)
    throws IOException, FileFormatException
  {
    checkFormat();

    GZIPOutputStream gOut = new GZIPOutputStream(stream);

    gOut.write(FILE_VERSION);

    gOut.write(mVersion);

    String fileName = getAdditionalFileName(file.toString());

    if(new File(fileName).isFile()) {
      new File(fileName).delete();
    }

    if(getProgramFrameCount() >= 254) {
      if(file != null) {
        FileOutputStream write = null;

        try {
          write = new FileOutputStream(fileName);
          writeProgCountToStream(write);
        }catch(Exception e) {e.printStackTrace();
          try {
            write.close();
          }catch(Exception e2) {}

          (new File(fileName)).delete();
        }
      }

      gOut.write(254);
    } else {
      gOut.write(getProgramFrameCount());
    }

    for (int i = 0; i < getProgramFrameCount(); i++) {
      ProgramFrame frame = getProgramFrameAt(i);
      frame.writeToStream(gOut);
    }

    gOut.close();
  }
  private String getAdditionalFileName(String fileName) {
    int index = fileName.indexOf("_update_");

    if(index != -1) {
      return fileName.substring(0,index) + fileName.substring(index+8,fileName.indexOf(".prog.gz")) + "_additional.prog.gz";
    } else {
      return fileName.substring(0,fileName.indexOf(".prog.gz")) + "_additional.prog.gz";
    }
  }

  public String getProgramFileName() {
    if (mChannel==null || mDate==null) {
      return null;
    }
    return getProgramFileName(mDate,mChannel);
  }


  public static String getProgramFileName(Date date, devplugin.Channel channel) {
    return getProgramFileName(date,channel.getCountry(),channel.getId());
  }


  public static String getProgramFileName(Date date, String country,
    String channel)
  {
    return getProgramFileName(date, country, channel, "raw", -1);
  }



  public static String getProgramFileName(Date date, String country,
    String channel, String level)
  {
    return getProgramFileName(date, country, channel, level, -1);
  }



  public static String getProgramFileName(Date date, String country,
    String channel, String level, int updateVersion)
  {
    StringBuilder buf = new StringBuilder(50);

    buf.append(date.getYear());
    buf.append('-');
    buf.append(date.getMonth() < 10 ? "0" : "");
    buf.append(date.getMonth());
    buf.append('-');
    buf.append(date.getDayOfMonth() < 10 ? "0" : "");
    buf.append(date.getDayOfMonth());
    buf.append('_');
    buf.append(country);
    buf.append('_');
    buf.append(channel);
    buf.append('_');
    buf.append(level);
    if (updateVersion > 0) {
      buf.append("_update_");
      buf.append(updateVersion);
      buf.append(".prog.gz");
    } else {
      buf.append("_full.prog.gz");
    }

    return buf.toString();
  }


  public static Date getDateFromFileName(String fileName)
    throws TvBrowserException
  {
    try {
      // E.g. '2003-10-04_de_premiere-1_base_update_15.prog.gz'
      //   or '2003-10-04_de_premiere-1_base_full.prog.gz'
      int year = Integer.parseInt(fileName.substring(0, 4));
      int month = Integer.parseInt(fileName.substring(5, 7));
      int day = Integer.parseInt(fileName.substring(8, 10));
      return new Date(year, month, day);
    }
    catch (Exception exc) {
      throw new TvBrowserException(DayProgramFile.class, "error.1",
        "Program file name has wrong syntax: {0}", fileName, exc);
    }
  }


  public static String getCountryFromFileName(String fileName)
    throws TvBrowserException
  {
    try {
      // E.g. '2003-10-04_de_premiere-1_base_update_15.prog.gz'
      //   or '2003-10-04_de_premiere-1_base_full.prog.gz'
      return fileName.substring(11, 13);
    }
    catch (Exception exc) {
      throw new TvBrowserException(DayProgramFile.class, "error.1",
        "Program file name has wrong syntax: {0}", fileName, exc);
    }
  }


  public static String getChannelNameFromFileName(String fileName)
    throws TvBrowserException
  {
    try {
      // E.g. '2003-10-04_de_premiere-1_base_update_15.prog.gz'
      //   or '2003-10-04_de_premiere-1_base_full.prog.gz'
      int channelEnd = fileName.indexOf('_', 14);
      return fileName.substring(14, channelEnd);
    }
    catch (Exception exc) {
      throw new TvBrowserException(DayProgramFile.class, "error.1",
        "Program file name has wrong syntax: {0}", fileName, exc);
    }
  }


  public static String getLevelFromFileName(String fileName)
    throws TvBrowserException
  {
    try {
      // E.g. '2003-10-04_de_premiere-1_base_update_15.prog.gz'
      //   or '2003-10-04_de_premiere-1_base_full.prog.gz'
      int channelEnd = fileName.indexOf('_', 14);
      int levelEnd = fileName.indexOf('_', channelEnd + 1);
      return fileName.substring(channelEnd + 1, levelEnd);
    }
    catch (Exception exc) {
      throw new TvBrowserException(DayProgramFile.class, "error.1",
        "Program file name has wrong syntax: {0}", fileName, exc);
    }
  }


  public static int getLevelIndexForId(String levelId) {
    for (int i = 0; i < LEVEL_ARR.length; i++) {
      if (levelId.equals(LEVEL_ARR[i].getId())) {
        return i;
      }
    }

    return -1;
  }


  public boolean equals(Object obj) {
    if (obj instanceof DayProgramFile) {
      DayProgramFile file = (DayProgramFile) obj;

      if (getProgramFrameCount() != file.getProgramFrameCount()) {
        return false;
      }

      for (int i = 0; i < getProgramFrameCount(); i++) {
        ProgramFrame frame = getProgramFrameAt(i);

        int index = file.getProgramFrameIndexForId(frame.getId());
        if (index == -1) {
          return false;
        } else {
          if (! frame.equals(file.getProgramFrameAt(index))) {
            return false;
          }
        }
      }

      return true;
    } else {
      return false;
    }
  }

  public static TvDataLevel[] getLevels() {
    return LEVEL_ARR.clone();
  }

}
TOP

Related Classes of tvbrowserdataservice.file.DayProgramFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.