/*
  ==============================================================================

   This file is part of the JUCE library - "Jules' Utility Class Extensions"
   Copyright 2004-7 by Raw Material Software ltd.

  ------------------------------------------------------------------------------

   JUCE can be redistributed and/or modified 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.

   JUCE 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 JUCE; if not, visit www.gnu.org/licenses or write to the
   Free Software Foundation, Inc., 59 Temple Place, Suite 330,
   Boston, MA 02111-1307 USA

  ------------------------------------------------------------------------------

   If you'd like to release a closed-source product which uses JUCE, commercial
   licenses are also available: visit www.rawmaterialsoftware.com/juce for
   more information.

  ==============================================================================
*/

// (This file gets included by juce_mac_NativeCode.mm, rather than being
// compiled on its own).
#if JUCE_INCLUDED_FILE && JUCE_QUICKTIME

#define theMovie ((QTMovie*) movie)

//==============================================================================
QuickTimeMovieComponent::QuickTimeMovieComponent()
    : movie (0)
{
    setOpaque (true);
    setVisible (true);

    QTMovieView* view = [[QTMovieView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)];
    setView (view);
}

QuickTimeMovieComponent::~QuickTimeMovieComponent()
{
    closeMovie();
    setView (0);
}

bool QuickTimeMovieComponent::isQuickTimeAvailable() throw()
{
    return true;
}

static QTMovie* openMovieFromStream (InputStream* movieStream, File& movieFile)
{
    // unfortunately, QTMovie objects can only be created on the main thread..
    jassert (MessageManager::getInstance()->isThisTheMessageThread());

    QTMovie* movie = 0;

    FileInputStream* const fin = dynamic_cast <FileInputStream*> (movieStream);

    if (fin != 0)
    {
        movieFile = fin->getFile();
        movie = [QTMovie movieWithFile: juceStringToNS (movieFile.getFullPathName())
                                 error: nil];
    }
    else
    {
        MemoryBlock temp;
        movieStream->readIntoMemoryBlock (temp);

        const char* const suffixesToTry[] = { ".mov", ".mp3", ".avi", ".m4a" };

        for (int i = 0; i < numElementsInArray (suffixesToTry); ++i)
        {
            movie = [QTMovie movieWithDataReference: [QTDataReference dataReferenceWithReferenceToData: [NSData dataWithBytes: temp.getData()
                                                                                                                       length: temp.getSize()]
                                                                                                  name: [NSString stringWithCString: suffixesToTry[i]]
                                                                                              MIMEType: @""]
                                              error: nil];

            if (movie != 0)
                break;
        }
    }

    return movie;
}

bool QuickTimeMovieComponent::loadMovie (InputStream* movieStream,
                                         const bool controllerVisible)
{
    closeMovie();

    if (getPeer() == 0)
    {
        // To open a movie, this component must be visible inside a functioning window, so that
        // the QT control can be assigned to the window.
        jassertfalse
        return false;
    }

    movie = openMovieFromStream (movieStream, movieFile);

    [theMovie retain];
    QTMovieView* view = (QTMovieView*) getView();
    [view setMovie: theMovie];
    [view setControllerVisible: controllerVisible];
    setLooping (looping);

    return movie != nil;
}

void QuickTimeMovieComponent::closeMovie()
{
    stop();
    QTMovieView* view = (QTMovieView*) getView();
    [view setMovie: nil];
    [theMovie release];
    movie = 0;
    movieFile = File::nonexistent;
}

bool QuickTimeMovieComponent::isMovieOpen() const
{
    return movie != nil;
}

const File QuickTimeMovieComponent::getCurrentMovieFile() const
{
    return movieFile;
}

void QuickTimeMovieComponent::play()
{
    [theMovie play];
}

void QuickTimeMovieComponent::stop()
{
    [theMovie stop];
}

bool QuickTimeMovieComponent::isPlaying() const
{
    return movie != 0  && [theMovie rate] != 0;
}

void QuickTimeMovieComponent::setPosition (const double seconds)
{
    if (movie != 0)
    {
        QTTime t;
        t.timeValue = (uint64) (100000.0 * seconds);
        t.timeScale = 100000;
        t.flags = 0;

        [theMovie setCurrentTime: t];
    }
}

double QuickTimeMovieComponent::getPosition() const
{
    if (movie == 0)
        return 0.0;

    QTTime t = [theMovie currentTime];
    return t.timeValue / (double) t.timeScale;
}

void QuickTimeMovieComponent::setSpeed (const float newSpeed)
{
    [theMovie setRate: newSpeed];
}

double QuickTimeMovieComponent::getMovieDuration() const
{
    if (movie == 0)
        return 0.0;

    QTTime t = [theMovie duration];
    return t.timeValue / (double) t.timeScale;
}

void QuickTimeMovieComponent::setLooping (const bool shouldLoop)
{
    looping = shouldLoop;

    [theMovie setAttribute: [NSNumber numberWithBool: shouldLoop]
                    forKey: QTMovieLoopsAttribute];
}

bool QuickTimeMovieComponent::isLooping() const
{
    return looping;
}

void QuickTimeMovieComponent::setMovieVolume (const float newVolume)
{
    [theMovie setVolume: newVolume];
}

float QuickTimeMovieComponent::getMovieVolume() const
{
    return movie != 0 ? [theMovie volume] : 0.0f;
}

void QuickTimeMovieComponent::getMovieNormalSize (int& width, int& height) const
{
    width = 0;
    height = 0;

    if (movie != 0)
    {
        NSSize s = [[theMovie attributeForKey: QTMovieNaturalSizeAttribute] sizeValue];
        width = s.width;
        height = s.height;
    }
}

void QuickTimeMovieComponent::paint (Graphics& g)
{
    if (movie == 0)
        g.fillAll (Colours::black);
}

bool QuickTimeMovieComponent::isControllerVisible() const
{
    return controllerVisible;
}

//==============================================================================
bool QuickTimeMovieComponent::loadMovie (const File& movieFile_,
                                         const bool isControllerVisible)
{
    const bool ok = loadMovie ((InputStream*) movieFile_.createInputStream(), isControllerVisible);
    movieFile = movieFile_;
    return ok;
}

void QuickTimeMovieComponent::goToStart()
{
    setPosition (0.0);
}

void QuickTimeMovieComponent::setBoundsWithCorrectAspectRatio (const Rectangle& spaceToFitWithin,
                                                               const RectanglePlacement& placement)
{
    int normalWidth, normalHeight;
    getMovieNormalSize (normalWidth, normalHeight);

    if (normalWidth > 0 && normalHeight > 0 && ! spaceToFitWithin.isEmpty())
    {
        double x = 0.0, y = 0.0, w = normalWidth, h = normalHeight;

        placement.applyTo (x, y, w, h,
                           spaceToFitWithin.getX(), spaceToFitWithin.getY(),
                           spaceToFitWithin.getWidth(), spaceToFitWithin.getHeight());

        if (w > 0 && h > 0)
        {
            setBounds (roundDoubleToInt (x), roundDoubleToInt (y),
                       roundDoubleToInt (w), roundDoubleToInt (h));
        }
    }
    else
    {
        setBounds (spaceToFitWithin);
    }
}


//==============================================================================
#if ! (JUCE_MAC && JUCE_64BIT)

bool juce_OpenQuickTimeMovieFromStream (InputStream* movieStream, Movie& result, Handle& dataHandle)
{
    if (movieStream == 0)
        return false;

    File file;
    QTMovie* movie = openMovieFromStream (movieStream, file);

    if (movie != nil)
        result = [movie quickTimeMovie];

    return movie != nil;
}

#endif

#endif
