1/*
2 * Copyright (C) 2012 Intel Corporation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ewk_download_job.h"
28
29#include "WKAPICast.h"
30#include "WKRetainPtr.h"
31#include "WKURLRequest.h"
32#include "ewk_download_job_private.h"
33#include "ewk_url_request_private.h"
34#include "ewk_url_response_private.h"
35#include <Ecore.h>
36
37using namespace WebKit;
38
39EwkDownloadJob::EwkDownloadJob(WKDownloadRef download, EwkView* viewImpl)
40    : m_download(download)
41    , m_viewImpl(viewImpl)
42    , m_state(EWK_DOWNLOAD_JOB_STATE_NOT_STARTED)
43    , m_startTime(-1)
44    , m_endTime(-1)
45    , m_downloaded(0)
46{ }
47
48/**
49 * @internal
50 * Queries the identifier for this download
51 */
52uint64_t EwkDownloadJob::id() const
53{
54    return WKDownloadGetID(m_download.get());
55}
56
57/**
58 * @internal
59 * Returns the view this download is attached to.
60 * The view is needed to send notification signals.
61 */
62EwkView* EwkDownloadJob::view() const
63{
64    return m_viewImpl;
65}
66
67Ewk_Download_Job_State ewk_download_job_state_get(const Ewk_Download_Job* download)
68{
69    EWK_OBJ_GET_IMPL_OR_RETURN(const EwkDownloadJob, download, impl, EWK_DOWNLOAD_JOB_STATE_UNKNOWN);
70
71    return impl->state();
72}
73
74Ewk_Download_Job_State EwkDownloadJob::state() const
75{
76    return m_state;
77}
78
79Ewk_Url_Request* ewk_download_job_request_get(const Ewk_Download_Job* download)
80{
81    EWK_OBJ_GET_IMPL_OR_RETURN(const EwkDownloadJob, download, impl, nullptr);
82
83    return impl->request();
84}
85
86EwkUrlRequest* EwkDownloadJob::request() const
87{
88    if (!m_request) {
89        WKRetainPtr<WKURLRequestRef> wkURLRequest(AdoptWK, WKDownloadCopyRequest(m_download.get()));
90        m_request = EwkUrlRequest::create(wkURLRequest.get());
91    }
92
93    return m_request.get();
94}
95
96Ewk_Url_Response* ewk_download_job_response_get(const Ewk_Download_Job* download)
97{
98    EWK_OBJ_GET_IMPL_OR_RETURN(const EwkDownloadJob, download, impl, nullptr);
99
100    return impl->response();
101}
102
103EwkUrlResponse* EwkDownloadJob::response() const
104{
105    return m_response.get();
106}
107
108const char* ewk_download_job_destination_get(const Ewk_Download_Job* download)
109{
110    EWK_OBJ_GET_IMPL_OR_RETURN(const EwkDownloadJob, download, impl, nullptr);
111
112    return impl->destination();
113}
114
115const char* EwkDownloadJob::destination() const
116{
117    return m_destination;
118}
119
120Eina_Bool ewk_download_job_destination_set(Ewk_Download_Job* download, const char* destination)
121{
122    EWK_OBJ_GET_IMPL_OR_RETURN(EwkDownloadJob, download, impl, false);
123    EINA_SAFETY_ON_NULL_RETURN_VAL(destination, false);
124
125    impl->setDestination(destination);
126
127    return true;
128}
129
130void EwkDownloadJob::setDestination(const char* destination)
131{
132    m_destination = destination;
133}
134
135const char* ewk_download_job_suggested_filename_get(const Ewk_Download_Job* download)
136{
137    EWK_OBJ_GET_IMPL_OR_RETURN(const EwkDownloadJob, download, impl, nullptr);
138
139    return impl->suggestedFileName();
140}
141
142const char* EwkDownloadJob::suggestedFileName() const
143{
144    return m_suggestedFilename;
145}
146
147Eina_Bool ewk_download_job_cancel(Ewk_Download_Job* download)
148{
149    EWK_OBJ_GET_IMPL_OR_RETURN(EwkDownloadJob, download, impl, false);
150
151    return impl->cancel();
152}
153
154bool EwkDownloadJob::cancel()
155{
156    if (m_state != EWK_DOWNLOAD_JOB_STATE_DOWNLOADING)
157        return false;
158
159    m_state = EWK_DOWNLOAD_JOB_STATE_CANCELLING;
160    WKDownloadCancel(m_download.get());
161
162    return true;
163}
164
165double ewk_download_job_estimated_progress_get(const Ewk_Download_Job* download)
166{
167    EWK_OBJ_GET_IMPL_OR_RETURN(const EwkDownloadJob, download, impl, 0);
168
169    return impl->estimatedProgress();
170}
171
172double EwkDownloadJob::estimatedProgress() const
173{
174    if (!m_response)
175        return 0;
176
177    const unsigned long contentLength = m_response->contentLength();
178    if (!contentLength)
179        return 0;
180
181    return static_cast<double>(m_downloaded) / contentLength;
182}
183
184double ewk_download_job_elapsed_time_get(const Ewk_Download_Job* download)
185{
186    EWK_OBJ_GET_IMPL_OR_RETURN(const EwkDownloadJob, download, impl, 0);
187
188    return impl->elapsedTime();
189}
190
191double EwkDownloadJob::elapsedTime() const
192{
193    // Download has not started yet.
194    if (m_startTime < 0)
195        return 0;
196
197    // Download had ended, return the time elapsed between the
198    // download start and the end event.
199    if (m_endTime >= 0)
200        return m_endTime - m_startTime;
201
202    // Download is still going.
203    return ecore_time_get() - m_startTime;
204}
205
206uint64_t ewk_download_job_received_data_size_get(const Ewk_Download_Job* download)
207{
208    EWK_OBJ_GET_IMPL_OR_RETURN(const EwkDownloadJob, download, impl, 0);
209
210    return impl->receivedDataSize();
211}
212
213uint64_t EwkDownloadJob::receivedDataSize() const
214{
215    return m_downloaded;
216}
217
218/**
219 * @internal
220 * Sets the URL @a response for this @a download.
221 */
222void EwkDownloadJob::setResponse(PassRefPtr<EwkUrlResponse> response)
223{
224    ASSERT(response);
225
226    m_response = response;
227}
228
229/**
230 * @internal
231 * Sets the suggested file name for this @a download.
232 */
233void EwkDownloadJob::setSuggestedFileName(const char* suggestedFilename)
234{
235    m_suggestedFilename = suggestedFilename;
236}
237
238/**
239 * @internal
240 * Report a given amount of data was received.
241 */
242void EwkDownloadJob::incrementReceivedData(uint64_t length)
243{
244    m_downloaded += length;
245}
246
247/**
248 * @internal
249 * Sets the state of the download.
250 */
251void EwkDownloadJob::setState(Ewk_Download_Job_State state)
252{
253    m_state = state;
254
255    switch (state) {
256    case EWK_DOWNLOAD_JOB_STATE_DOWNLOADING:
257        m_startTime = ecore_time_get();
258        break;
259    case EWK_DOWNLOAD_JOB_STATE_FAILED:
260    case EWK_DOWNLOAD_JOB_STATE_CANCELLED:
261    case EWK_DOWNLOAD_JOB_STATE_FINISHED:
262        m_endTime = ecore_time_get();
263        break;
264    default:
265        break;
266    }
267}
268