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

   This file is part of the JUCE library.
   Copyright (c) 2015 - ROLI Ltd.

   Permission is granted to use this software under the terms of either:
   a) the GPL v2 (or any later version)
   b) the Affero GPL v3

   Details of these licenses can be found at: www.gnu.org/licenses

   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.

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

   To release a closed-source product which uses JUCE, commercial licenses are
   available: visit www.juce.com for more information.

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

#if JUCE_IOS
 using BaseClass = UIViewComponent;
#else
 using BaseClass = NSViewComponent;
#endif

struct VideoComponent::Pimpl   : public BaseClass
{
    Pimpl()
    {
        setVisible (true);

       #if JUCE_MAC && JUCE_32BIT
        auto view = [[NSView alloc] init];  // 32-bit builds don't have AVPlayerView, so need to use a layer
        controller = [[AVPlayerLayer alloc] init];
        setView (view);
        [view setNextResponder: [view superview]];
        [view setWantsLayer: YES];
        [view setLayer: controller];
        [view release];
       #elif JUCE_MAC
        controller = [[AVPlayerView alloc] init];
        setView (controller);
        [controller setNextResponder: [controller superview]];
        [controller setWantsLayer: YES];
       #else
        controller = [[AVPlayerViewController alloc] init];
        setView ([controller view]);
       #endif
    }

    ~Pimpl()
    {
        close();
        setView (nil);
        [controller release];
    }

    Result load (const File& file)
    {
        auto r = load (createNSURLFromFile (file));

        if (r.wasOk())
            currentFile = file;

        return r;
    }

    Result load (const URL& url)
    {
        auto r = load ([NSURL URLWithString: juceStringToNS (url.toString (true))]);

        if (r.wasOk())
            currentURL = url;

        return r;
    }

    Result load (NSURL* url)
    {
        if (url != nil)
        {
            close();

            if (auto* player = [AVPlayer playerWithURL: url])
            {
                [controller setPlayer: player];
                return Result::ok();
            }
        }

        return Result::fail ("Couldn't open movie");
    }

    void close()
    {
        stop();
        [controller setPlayer: nil];
        currentFile = File();
        currentURL = {};
    }

    bool isOpen() const noexcept        { return getAVPlayer() != nil; }
    bool isPlaying() const noexcept     { return getSpeed() != 0; }

    void play() noexcept                { [getAVPlayer() play]; }
    void stop() noexcept                { [getAVPlayer() pause]; }

    void setPosition (double newPosition)
    {
        if (auto* p = getAVPlayer())
        {
            CMTime t = { (CMTimeValue) (100000.0 * newPosition),
                         (CMTimeScale) 100000, kCMTimeFlags_Valid };

            [p seekToTime: t
          toleranceBefore: kCMTimeZero
           toleranceAfter: kCMTimeZero];
        }
    }

    double getPosition() const
    {
        if (auto* p = getAVPlayer())
            return toSeconds ([p currentTime]);

        return 0.0;
    }

    void setSpeed (double newSpeed)
    {
        [getAVPlayer() setRate: (float) newSpeed];
    }

    double getSpeed() const
    {
        if (auto* p = getAVPlayer())
            return [p rate];

        return 0.0;
    }

    Rectangle<int> getNativeSize() const
    {
        if (auto* player = getAVPlayer())
        {
            auto s = [[player currentItem] presentationSize];
            return { (int) s.width, (int) s.height };
        }

        return {};
    }

    double getDuration() const
    {
        if (auto* player = getAVPlayer())
            return toSeconds ([[player currentItem] duration]);

        return 0.0;
    }

    void setVolume (float newVolume)
    {
        [getAVPlayer() setVolume: newVolume];
    }

    float getVolume() const
    {
        if (auto* p = getAVPlayer())
            return [p volume];

        return 0.0f;
    }

    File currentFile;
    URL currentURL;

private:
   #if JUCE_IOS
    AVPlayerViewController* controller = nil;
   #elif JUCE_32BIT
    AVPlayerLayer* controller = nil;
   #else
    AVPlayerView* controller = nil;
   #endif

    AVPlayer* getAVPlayer() const noexcept   { return [controller player]; }

    static double toSeconds (const CMTime& t) noexcept
    {
        return t.timescale != 0 ? (t.value / (double) t.timescale) : 0.0;
    }

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
};